WIP: Vulkan: Initial Immediate Mode Support. #106954

Closed
Jeroen Bakker wants to merge 27 commits from Jeroen-Bakker:vulkan-immediate into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
569 changed files with 6853 additions and 6198 deletions
Showing only changes of commit e3e3037a4d - Show all commits

View File

@ -6,15 +6,24 @@
set(EMBREE_EXTRA_ARGS
-DEMBREE_ISPC_SUPPORT=OFF
-DEMBREE_TUTORIALS=OFF
-DEMBREE_STATIC_LIB=ON
-DEMBREE_STATIC_LIB=OFF
-DEMBREE_RAY_MASK=ON
-DEMBREE_FILTER_FUNCTION=ON
-DEMBREE_BACKFACE_CULLING=OFF
-DEMBREE_BACKFACE_CULLING_CURVES=ON
-DEMBREE_BACKFACE_CULLING_SPHERES=ON
-DEMBREE_TASKING_SYSTEM=TBB
-DEMBREE_TBB_ROOT=${LIBDIR}/tbb
-DTBB_ROOT=${LIBDIR}/tbb
)
if(WIN32)
set(EMBREE_EXTRA_ARGS
${EMBREE_EXTRA_ARGS}
-DCMAKE_DEBUG_POSTFIX=_d
)
endif()
if(NOT BLENDER_PLATFORM_ARM)
set(EMBREE_EXTRA_ARGS
${EMBREE_EXTRA_ARGS}
@ -45,25 +54,19 @@ add_dependencies(
)
if(WIN32)
if(BUILD_MODE STREQUAL Release)
ExternalProject_Add_Step(external_embree after_install
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/embree ${HARVEST_TARGET}/embree
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/embree/include ${HARVEST_TARGET}/embree/include
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/embree/lib ${HARVEST_TARGET}/embree/lib
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/embree/share ${HARVEST_TARGET}/embree/share
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/bin/embree4.dll ${HARVEST_TARGET}/embree/bin/embree4.dll
DEPENDEES install
)
else()
ExternalProject_Add_Step(external_embree after_install
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/embree3.lib ${HARVEST_TARGET}/embree/lib/embree3_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/embree_avx.lib ${HARVEST_TARGET}/embree/lib/embree_avx_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/embree_avx2.lib ${HARVEST_TARGET}/embree/lib/embree_avx2_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/embree_sse42.lib ${HARVEST_TARGET}/embree/lib/embree_sse42_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/lexers.lib ${HARVEST_TARGET}/embree/lib/lexers_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/math.lib ${HARVEST_TARGET}/embree/lib/math_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/simd.lib ${HARVEST_TARGET}/embree/lib/simd_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/sys.lib ${HARVEST_TARGET}/embree/lib/sys_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/tasking.lib ${HARVEST_TARGET}/embree/lib/tasking_d.lib
DEPENDEES install
)
endif()
ExternalProject_Add_Step(external_embree after_install
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/bin/embree4_d.dll ${HARVEST_TARGET}/embree/bin/embree4_d.dll
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/embree4_d.lib ${HARVEST_TARGET}/embree/lib/embree4_d.lib
DEPENDEES install
)
endif()
endif()

View File

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

View File

@ -478,9 +478,9 @@ set(SQLITE_HASH_TYPE SHA1)
set(SQLITE_FILE sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz)
set(SQLITE_CPE "cpe:2.3:a:sqlite:sqlite:${SQLITE_VERSION}:*:*:*:*:*:*:*")
set(EMBREE_VERSION 3.13.4)
set(EMBREE_VERSION 4.0.1)
set(EMBREE_URI https://github.com/embree/embree/archive/v${EMBREE_VERSION}.zip)
set(EMBREE_HASH 52d0be294d6c88ba7a6c9e046796e7be)
set(EMBREE_HASH dd26617719a587e126b341d1b32f7fd0)
set(EMBREE_HASH_TYPE MD5)
set(EMBREE_FILE embree-v${EMBREE_VERSION}.zip)
@ -534,10 +534,10 @@ set(WL_PROTOCOLS_URI https://gitlab.freedesktop.org/wayland/wayland-protocols/-/
set(WL_PROTOCOLS_HASH a28ff59a56e2ebb746048b6ef8d931d6)
set(WL_PROTOCOLS_HASH_TYPE MD5)
set(WAYLAND_VERSION 1.21.0)
set(WAYLAND_VERSION 1.22.0)
set(WAYLAND_FILE wayland-${WAYLAND_VERSION}.tar.xz)
set(WAYLAND_URI https://gitlab.freedesktop.org/wayland/wayland/-/releases/1.21.0/downloads/wayland-${WAYLAND_VERSION}.tar.xz)
set(WAYLAND_HASH f2653a2293bcd882d756c6a83d278903)
set(WAYLAND_URI https://gitlab.freedesktop.org/wayland/wayland/-/releases/${WAYLAND_VERSION}/downloads/wayland-${WAYLAND_VERSION}.tar.xz)
set(WAYLAND_HASH 7410ab549e3928fce9381455b17b0803)
set(WAYLAND_HASH_TYPE MD5)
set(WAYLAND_LIBDECOR_VERSION 0.1.0)

View File

@ -1,19 +1,8 @@
diff -Naur org/kernels/rtcore_config.h.in embree-3.13.4/kernels/rtcore_config.h.in
--- org/kernels/rtcore_config.h.in 2022-06-14 22:13:52 -0600
+++ embree-3.13.4/kernels/rtcore_config.h.in 2022-06-24 15:20:12 -0600
@@ -14,6 +14,7 @@
#cmakedefine01 EMBREE_MIN_WIDTH
#define RTC_MIN_WIDTH EMBREE_MIN_WIDTH
+#cmakedefine EMBREE_STATIC_LIB
#cmakedefine EMBREE_API_NAMESPACE
#if defined(EMBREE_API_NAMESPACE)
diff --git a/kernels/CMakeLists.txt b/kernels/CMakeLists.txt
index 7c2f43d..106b1d5 100644
--- a/kernels/CMakeLists.txt
+++ b/kernels/CMakeLists.txt
@@ -201,6 +201,12 @@ embree_files(EMBREE_LIBRARY_FILES_AVX512 ${AVX512})
@@ -208,6 +208,12 @@ embree_files(EMBREE_LIBRARY_FILES_AVX512 ${AVX512})
#message("AVX2: ${EMBREE_LIBRARY_FILES_AVX2}")
#message("AVX512: ${EMBREE_LIBRARY_FILES_AVX512}")
@ -26,7 +15,7 @@ index 7c2f43d..106b1d5 100644
# replaces all .cpp files with a dummy file that includes that .cpp file
# this is to work around an ICC name mangling issue related to lambda functions under windows
MACRO (CreateISADummyFiles list isa)
@@ -277,7 +283,7 @@ IF (EMBREE_ISA_AVX AND EMBREE_LIBRARY_FILES_AVX)
@@ -311,7 +317,7 @@ IF (EMBREE_ISA_AVX AND EMBREE_LIBRARY_FILES_AVX)
ENDIF()
ENDIF()
@ -35,3 +24,128 @@ index 7c2f43d..106b1d5 100644
DISABLE_STACK_PROTECTOR_FOR_INTERSECTORS(${EMBREE_LIBRARY_FILES_AVX2})
ADD_LIBRARY(embree_avx2 STATIC ${EMBREE_LIBRARY_FILES_AVX2})
TARGET_LINK_LIBRARIES(embree_avx2 PRIVATE tasking)
diff --git a/include/embree4/rtcore_device.h b/include/embree4/rtcore_device.h
index 45bf95583..62ee7787d 100644
--- a/include/embree4/rtcore_device.h
+++ b/include/embree4/rtcore_device.h
@@ -55,6 +55,7 @@ enum RTCDeviceProperty
RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED = 66,
RTC_DEVICE_PROPERTY_IGNORE_INVALID_RAYS_ENABLED = 67,
RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED = 68,
+ RTC_DEVICE_PROPERTY_BACKFACE_CULLING_SPHERES_ENABLED = 69,
RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED = 96,
RTC_DEVICE_PROPERTY_QUAD_GEOMETRY_SUPPORTED = 97,
diff --git a/kernels/common/device.cpp b/kernels/common/device.cpp
index 3ffac7e37..215ccc961 100644
--- a/kernels/common/device.cpp
+++ b/kernels/common/device.cpp
@@ -170,6 +170,9 @@ namespace embree
#if defined (EMBREE_BACKFACE_CULLING_CURVES)
v += "backfacecullingcurves ";
#endif
+#if defined (EMBREE_BACKFACE_CULLING_SPHERES)
+ v += "backfacecullingspheres ";
+#endif
#if defined(EMBREE_FILTER_FUNCTION)
v += "intersection_filter ";
#endif
@@ -477,6 +480,12 @@ namespace embree
case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_CURVES_ENABLED: return 0;
#endif
+#if defined(EMBREE_BACKFACE_CULLING_SPHERES)
+ case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_SPHERES_ENABLED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_SPHERES_ENABLED: return 0;
+#endif
+
#if defined(EMBREE_COMPACT_POLYS)
case RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED: return 1;
#else
diff --git a/kernels/config.h.in b/kernels/config.h.in
index f02c90360..ba9acde56 100644
--- a/kernels/config.h.in
+++ b/kernels/config.h.in
@@ -5,6 +5,7 @@
#cmakedefine EMBREE_STAT_COUNTERS
#cmakedefine EMBREE_BACKFACE_CULLING
#cmakedefine EMBREE_BACKFACE_CULLING_CURVES
+#cmakedefine EMBREE_BACKFACE_CULLING_SPHERES
#cmakedefine EMBREE_FILTER_FUNCTION
#cmakedefine EMBREE_IGNORE_INVALID_RAYS
#cmakedefine EMBREE_GEOMETRY_TRIANGLE
diff --git a/kernels/geometry/sphere_intersector.h b/kernels/geometry/sphere_intersector.h
index 074f910a2..30f490818 100644
--- a/kernels/geometry/sphere_intersector.h
+++ b/kernels/geometry/sphere_intersector.h
@@ -106,8 +106,13 @@ namespace embree
const vbool<M> valid_front = valid & (ray.tnear() <= t_front) & (t_front <= ray.tfar);
const vbool<M> valid_back = valid & (ray.tnear() <= t_back ) & (t_back <= ray.tfar);
+#if defined (EMBREE_BACKFACE_CULLING_SPHERES)
+ /* check if there is a first hit */
+ const vbool<M> valid_first = valid_front;
+#else
/* check if there is a first hit */
const vbool<M> valid_first = valid_front | valid_back;
+#endif
if (unlikely(none(valid_first)))
return false;
@@ -120,7 +125,8 @@ namespace embree
/* invoke intersection filter for first hit */
const bool is_hit_first = epilog(valid_first, hit);
-
+
+#if !defined (EMBREE_BACKFACE_CULLING_SPHERES)
/* check for possible second hits before potentially accepted hit */
const vfloat<M> t_second = t_back;
const vbool<M> valid_second = valid_front & valid_back & (t_second <= ray.tfar);
@@ -131,7 +137,9 @@ namespace embree
const Vec3vf<M> Ng_second = td_back * ray_dir - perp;
hit = SphereIntersectorHitM<M> (t_second, Ng_second);
const bool is_hit_second = epilog(valid_second, hit);
-
+#else
+ constexpr bool is_hit_second = false;
+#endif
return is_hit_first | is_hit_second;
}
@@ -186,8 +194,13 @@ namespace embree
const vbool<M> valid_front = valid & (ray.tnear()[k] <= t_front) & (t_front <= ray.tfar[k]);
const vbool<M> valid_back = valid & (ray.tnear()[k] <= t_back ) & (t_back <= ray.tfar[k]);
+#if defined (EMBREE_BACKFACE_CULLING_SPHERES)
+ /* check if there is a first hit */
+ const vbool<M> valid_first = valid_front;
+#else
/* check if there is a first hit */
const vbool<M> valid_first = valid_front | valid_back;
+#endif
if (unlikely(none(valid_first)))
return false;
@@ -200,7 +213,8 @@ namespace embree
/* invoke intersection filter for first hit */
const bool is_hit_first = epilog(valid_first, hit);
-
+
+#if !defined (EMBREE_BACKFACE_CULLING_SPHERES)
/* check for possible second hits before potentially accepted hit */
const vfloat<M> t_second = t_back;
const vbool<M> valid_second = valid_front & valid_back & (t_second <= ray.tfar[k]);
@@ -211,7 +225,9 @@ namespace embree
const Vec3vf<M> Ng_second = td_back * ray_dir - perp;
hit = SphereIntersectorHitM<M> (t_second, Ng_second);
const bool is_hit_second = epilog(valid_second, hit);
-
+#else
+ constexpr bool is_hit_second = false;
+#endif
return is_hit_first | is_hit_second;
}
};

View File

@ -23,6 +23,7 @@ SET(_embree_SEARCH_DIRS
FIND_PATH(EMBREE_INCLUDE_DIR
NAMES
embree4/rtcore.h
embree3/rtcore.h
HINTS
${_embree_SEARCH_DIRS}
@ -30,28 +31,67 @@ FIND_PATH(EMBREE_INCLUDE_DIR
include
)
IF(NOT (("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64") OR (APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))))
SET(_embree_SIMD_COMPONENTS
embree_sse42
embree_avx
embree_avx2
)
IF(EXISTS ${EMBREE_INCLUDE_DIR}/embree4/rtcore_config.h)
SET(EMBREE_MAJOR_VERSION 4)
ELSE()
SET(EMBREE_MAJOR_VERSION 3)
ENDIF()
SET(_embree_FIND_COMPONENTS
embree3
${_embree_SIMD_COMPONENTS}
lexers
math
simd
sys
tasking
)
IF(EMBREE_INCLUDE_DIR)
FILE(READ ${EMBREE_INCLUDE_DIR}/embree${EMBREE_MAJOR_VERSION}/rtcore_config.h _embree_config_header)
IF(_embree_config_header MATCHES "#define EMBREE_STATIC_LIB")
SET(EMBREE_STATIC_LIB TRUE)
ELSE()
SET(EMBREE_STATIC_LIB FALSE)
ENDIF()
IF(_embree_config_header MATCHES "#define EMBREE_SYCL_SUPPORT")
SET(EMBREE_SYCL_SUPPORT TRUE)
ELSE()
SET(EMBREE_SYCL_SUPPORT FALSE)
ENDIF()
UNSET(_embree_config_header)
ENDIF()
IF(EMBREE_STATIC_LIB)
IF(NOT (("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64") OR (APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))))
SET(_embree_SIMD_COMPONENTS
embree_sse42
embree_avx
embree_avx2
)
ENDIF()
IF(EMBREE_SYCL_SUPPORT)
SET(_embree_GPU_COMPONENTS
embree4_sycl
embree_rthwif
)
ENDIF()
SET(_embree_FIND_COMPONENTS
embree${EMBREE_MAJOR_VERSION}
${_embree_SIMD_COMPONENTS}
${_embree_GPU_COMPONENTS}
lexers
math
simd
sys
tasking
)
ELSE()
SET(_embree_FIND_COMPONENTS
embree${EMBREE_MAJOR_VERSION}
)
IF(EMBREE_SYCL_SUPPORT)
LIST(APPEND _embree_FIND_COMPONENTS
embree4_sycl
)
ENDIF()
ENDIF()
SET(_embree_LIBRARIES)
FOREACH(COMPONENT ${_embree_FIND_COMPONENTS})
STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
FIND_LIBRARY(EMBREE_${UPPERCOMPONENT}_LIBRARY
NAMES
${COMPONENT}
@ -60,18 +100,9 @@ FOREACH(COMPONENT ${_embree_FIND_COMPONENTS})
PATH_SUFFIXES
lib64 lib
)
IF(NOT EMBREE_${UPPERCOMPONENT}_LIBRARY)
IF(EMBREE_EMBREE3_LIBRARY)
# If we can't find all the static libraries, try to fall back to the shared library if found.
# This allows building with a shared embree library
SET(_embree_LIBRARIES ${EMBREE_EMBREE3_LIBRARY})
BREAK()
ENDIF()
ENDIF()
LIST(APPEND _embree_LIBRARIES "${EMBREE_${UPPERCOMPONENT}_LIBRARY}")
ENDFOREACH()
# handle the QUIETLY and REQUIRED arguments and set EMBREE_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
@ -85,6 +116,9 @@ ENDIF()
MARK_AS_ADVANCED(
EMBREE_INCLUDE_DIR
EMBREE_MAJOR_VERSION
EMBREE_SYCL_SUPPORT
EMBREE_STATIC_LIB
)
FOREACH(COMPONENT ${_embree_FIND_COMPONENTS})

View File

@ -108,6 +108,7 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(SYCL
IF(SYCL_FOUND)
SET(SYCL_INCLUDE_DIR ${SYCL_INCLUDE_DIR} ${SYCL_INCLUDE_DIR}/sycl)
SET(SYCL_LIBRARIES ${SYCL_LIBRARY})
ELSE()
SET(SYCL_SYCL_FOUND FALSE)
ENDIF()

View File

@ -1364,3 +1364,24 @@ macro(windows_generate_shared_manifest)
)
endif()
endmacro()
macro(windows_process_platform_bundled_libraries library_deps)
if(NOT "${library_deps}" STREQUAL "")
set(next_library_mode "ALL")
foreach(library ${library_deps})
string(TOUPPER "${library}" library_upper)
if(("${library_upper}" STREQUAL "RELEASE") OR
("${library_upper}" STREQUAL "DEBUG") OR
("${library_upper}" STREQUAL "ALL"))
set(next_library_mode "${library_upper}")
else()
windows_install_shared_manifest(
FILES ${library}
${next_library_mode}
)
set(next_library_mode "ALL")
endif()
endforeach()
endif()
endmacro()

View File

@ -330,6 +330,7 @@ if(WITH_CYCLES AND WITH_CYCLES_EMBREE)
endforeach()
set(EMBREE_LIBRARIES ${_embree_libraries_force_load})
endif()
add_bundled_libraries(embree/lib)
if(WITH_OPENIMAGEDENOISE)
find_package(OpenImageDenoise REQUIRED)

View File

@ -317,7 +317,7 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL)
endif()
endif()
if(WITH_CYCLES AND WITH_CYCLES_DEVICE_ONEAPI)
if(WITH_CYCLES AND (WITH_CYCLES_DEVICE_ONEAPI OR (WITH_CYCLES_EMBREE AND EMBREE_SYCL_SUPPORT)))
set(CYCLES_LEVEL_ZERO ${LIBDIR}/level-zero CACHE PATH "Path to Level Zero installation")
if(EXISTS ${CYCLES_LEVEL_ZERO} AND NOT LEVEL_ZERO_ROOT_DIR)
set(LEVEL_ZERO_ROOT_DIR ${CYCLES_LEVEL_ZERO})
@ -453,6 +453,7 @@ add_bundled_libraries(opencolorio/lib)
if(WITH_CYCLES AND WITH_CYCLES_EMBREE)
find_package(Embree 3.8.0 REQUIRED)
endif()
add_bundled_libraries(embree/lib)
if(WITH_OPENIMAGEDENOISE)
find_package_wrapper(OpenImageDenoise)

View File

@ -850,27 +850,75 @@ endif()
if(WITH_CYCLES AND WITH_CYCLES_EMBREE)
windows_find_package(Embree)
if(NOT Embree_FOUND)
set(EMBREE_ROOT_DIR ${LIBDIR}/embree)
set(EMBREE_INCLUDE_DIRS ${LIBDIR}/embree/include)
set(EMBREE_LIBRARIES
optimized ${LIBDIR}/embree/lib/embree3.lib
optimized ${LIBDIR}/embree/lib/embree_avx2.lib
optimized ${LIBDIR}/embree/lib/embree_avx.lib
optimized ${LIBDIR}/embree/lib/embree_sse42.lib
optimized ${LIBDIR}/embree/lib/lexers.lib
optimized ${LIBDIR}/embree/lib/math.lib
optimized ${LIBDIR}/embree/lib/simd.lib
optimized ${LIBDIR}/embree/lib/sys.lib
optimized ${LIBDIR}/embree/lib/tasking.lib
debug ${LIBDIR}/embree/lib/embree3_d.lib
debug ${LIBDIR}/embree/lib/embree_avx2_d.lib
debug ${LIBDIR}/embree/lib/embree_avx_d.lib
debug ${LIBDIR}/embree/lib/embree_sse42_d.lib
debug ${LIBDIR}/embree/lib/lexers_d.lib
debug ${LIBDIR}/embree/lib/math_d.lib
debug ${LIBDIR}/embree/lib/simd_d.lib
debug ${LIBDIR}/embree/lib/sys_d.lib
debug ${LIBDIR}/embree/lib/tasking_d.lib
if(EXISTS ${LIBDIR}/embree/include/embree4/rtcore_config.h)
set(EMBREE_MAJOR_VERSION 4)
else()
set(EMBREE_MAJOR_VERSION 3)
endif()
file(READ ${LIBDIR}/embree/include/embree${EMBREE_MAJOR_VERSION}/rtcore_config.h _embree_config_header)
if(_embree_config_header MATCHES "#define EMBREE_STATIC_LIB")
set(EMBREE_STATIC_LIB TRUE)
else()
set(EMBREE_STATIC_LIB FALSE)
endif()
if(_embree_config_header MATCHES "#define EMBREE_SYCL_SUPPORT")
set(EMBREE_SYCL_SUPPORT TRUE)
else()
set(EMBREE_SYCL_SUPPORT FALSE)
endif()
set(EMBREE_LIBRARIES
optimized ${LIBDIR}/embree/lib/embree${EMBREE_MAJOR_VERSION}.lib
debug ${LIBDIR}/embree/lib/embree${EMBREE_MAJOR_VERSION}_d.lib
)
if(EMBREE_SYCL_SUPPORT)
set(EMBREE_LIBRARIES
${EMBREE_LIBRARIES}
optimized ${LIBDIR}/embree/lib/embree4_sycl.lib
debug ${LIBDIR}/embree/lib/embree4_sycl_d.lib
)
endif()
if(EMBREE_STATIC_LIB)
set(EMBREE_LIBRARIES
${EMBREE_LIBRARIES}
optimized ${LIBDIR}/embree/lib/embree_avx2.lib
optimized ${LIBDIR}/embree/lib/embree_avx.lib
optimized ${LIBDIR}/embree/lib/embree_sse42.lib
optimized ${LIBDIR}/embree/lib/lexers.lib
optimized ${LIBDIR}/embree/lib/math.lib
optimized ${LIBDIR}/embree/lib/simd.lib
optimized ${LIBDIR}/embree/lib/sys.lib
optimized ${LIBDIR}/embree/lib/tasking.lib
debug ${LIBDIR}/embree/lib/embree_avx2_d.lib
debug ${LIBDIR}/embree/lib/embree_avx_d.lib
debug ${LIBDIR}/embree/lib/embree_sse42_d.lib
debug ${LIBDIR}/embree/lib/lexers_d.lib
debug ${LIBDIR}/embree/lib/math_d.lib
debug ${LIBDIR}/embree/lib/simd_d.lib
debug ${LIBDIR}/embree/lib/sys_d.lib
debug ${LIBDIR}/embree/lib/tasking_d.lib
)
if(EMBREE_SYCL_SUPPORT)
set(EMBREE_LIBRARIES
${EMBREE_LIBRARIES}
optimized ${LIBDIR}/embree/lib/embree_rthwif.lib
debug ${LIBDIR}/embree/lib/embree_rthwif_d.lib
)
endif()
endif()
endif()
if(NOT EMBREE_STATIC_LIB)
list(APPEND PLATFORM_BUNDLED_LIBRARIES
RELEASE ${EMBREE_ROOT_DIR}/bin/embree${EMBREE_MAJOR_VERSION}.dll
DEBUG ${EMBREE_ROOT_DIR}/bin/embree${EMBREE_MAJOR_VERSION}_d.dll
)
endif()
endif()
@ -1029,7 +1077,7 @@ endif()
set(ZSTD_INCLUDE_DIRS ${LIBDIR}/zstd/include)
set(ZSTD_LIBRARIES ${LIBDIR}/zstd/lib/zstd_static.lib)
if(WITH_CYCLES AND WITH_CYCLES_DEVICE_ONEAPI)
if(WITH_CYCLES AND (WITH_CYCLES_DEVICE_ONEAPI OR (WITH_CYCLES_EMBREE AND EMBREE_SYCL_SUPPORT)))
set(LEVEL_ZERO_ROOT_DIR ${LIBDIR}/level_zero)
set(CYCLES_SYCL ${LIBDIR}/dpcpp CACHE PATH "Path to oneAPI DPC++ compiler")
if(EXISTS ${CYCLES_SYCL} AND NOT SYCL_ROOT_DIR)
@ -1040,8 +1088,9 @@ if(WITH_CYCLES AND WITH_CYCLES_DEVICE_ONEAPI)
${SYCL_ROOT_DIR}/bin/sycl[0-9].dll
)
foreach(sycl_runtime_library IN LISTS _sycl_runtime_libraries_glob)
string(REPLACE ".dll" "$<$<CONFIG:Debug>:d>.dll" sycl_runtime_library ${sycl_runtime_library})
list(APPEND _sycl_runtime_libraries ${sycl_runtime_library})
string(REPLACE ".dll" "_d.dll" sycl_runtime_library_debug ${sycl_runtime_library})
list(APPEND _sycl_runtime_libraries RELEASE ${sycl_runtime_library})
list(APPEND _sycl_runtime_libraries DEBUG ${sycl_runtime_library_debug})
endforeach()
unset(_sycl_runtime_libraries_glob)
@ -1054,6 +1103,8 @@ if(WITH_CYCLES AND WITH_CYCLES_DEVICE_ONEAPI)
list(APPEND PLATFORM_BUNDLED_LIBRARIES ${_sycl_runtime_libraries})
unset(_sycl_runtime_libraries)
set(SYCL_LIBRARIES optimized ${SYCL_LIBRARY} debug ${SYCL_LIBRARY_DEBUG})
endif()

View File

@ -112,6 +112,7 @@ def create_manifest(
print(f'Building manifest of files: "{outpath}"...', end="", flush=True)
with outpath.open("w", encoding="utf-8") as outfile:
main_files_to_manifest(blender_srcdir, outfile)
assets_to_manifest(blender_srcdir, outfile)
submodules_to_manifest(blender_srcdir, version, outfile)
if packages_dir:
@ -140,6 +141,18 @@ def submodules_to_manifest(
print(path, file=outfile)
def assets_to_manifest(blender_srcdir: Path, outfile: TextIO) -> None:
assert not blender_srcdir.is_absolute()
assets_dir = blender_srcdir.parent / "lib" / "assets"
for path in assets_dir.glob("*"):
if path.name == "working":
continue
if path.name in SKIP_NAMES:
continue
print(path, file=outfile)
def packages_to_manifest(outfile: TextIO, packages_dir: Path) -> None:
for path in packages_dir.glob("*"):
if not path.is_file():
@ -170,7 +183,9 @@ def create_tarball(
command += [
"--transform",
f"s,^{blender_srcdir.name}/,blender-{version}/,g",
"--use-compress-program=xz -9",
"--transform",
f"s,^lib/assets/,blender-{version}/release/datafiles/assets/,g",
"--use-compress-program=xz -1",
"--create",
f"--file={tarball}",
f"--files-from={manifest}",

View File

@ -1853,8 +1853,6 @@ def pyrna2sphinx(basepath):
fw(" %s\n\n" % operator_description)
for prop in op.args:
write_param(" ", fw, prop)
if op.args:
fw("\n")
location = op.get_location()
if location != (None, None):
@ -1865,9 +1863,12 @@ def pyrna2sphinx(basepath):
else:
url_base = API_BASEURL
fw(" :file:`%s\\:%d <%s/%s#L%d>`_\n\n" %
fw(" :File: `%s\\:%d <%s/%s#L%d>`__\n\n" %
(location[0], location[1], url_base, location[0], location[1]))
if op.args:
fw("\n")
file.close()
if "bpy.ops" not in EXCLUDE_MODULES:

View File

@ -127,7 +127,7 @@ typedef uint32_t cuuint32_t;
typedef uint64_t cuuint64_t;
#endif
#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) || defined (__aarch64__)
#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) || defined (__aarch64__) || defined(__ppc64__) || defined(__PPC64__)
typedef unsigned long long CUdeviceptr;
#else
typedef unsigned int CUdeviceptr;

View File

@ -84,7 +84,7 @@ typedef uint32_t hipuint32_t;
typedef uint64_t hipuint64_t;
#endif
#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) || defined (__aarch64__)
#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) || defined (__aarch64__) || defined(__ppc64__) || defined(__PPC64__)
typedef unsigned long long hipDeviceptr_t;
#else
typedef unsigned int hipDeviceptr_t;

View File

@ -281,6 +281,7 @@ endif()
if(WITH_CYCLES_EMBREE)
add_definitions(-DWITH_EMBREE)
add_definitions(-DEMBREE_MAJOR_VERSION=${EMBREE_MAJOR_VERSION})
include_directories(
SYSTEM
${EMBREE_INCLUDE_DIRS}

View File

@ -51,6 +51,12 @@ if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI)
endif()
if(WITH_USD)
# Silence warning from USD headers using deprecated TBB header.
add_definitions(
-D__TBB_show_deprecation_message_atomic_H
-D__TBB_show_deprecation_message_task_H
)
list(APPEND INC_SYS
${USD_INCLUDE_DIRS}
)

View File

@ -403,7 +403,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
time_limit: FloatProperty(
name="Time Limit",
description="Limit the render time (excluding synchronization time)."
description="Limit the render time (excluding synchronization time). "
"Zero disables the limit",
min=0.0,
default=0.0,

View File

@ -230,7 +230,7 @@ class DisplayGPUTexture {
}
GPU_texture_filter_mode(gpu_texture, false);
GPU_texture_wrap_mode(gpu_texture, false, true);
GPU_texture_extend_mode(gpu_texture, GPU_SAMPLER_EXTEND_MODE_EXTEND);
++num_used;
@ -705,14 +705,14 @@ static void draw_tile(const float2 &zoom,
const float zoomed_height = draw_tile.params.size.y * zoom.y;
if (texture.width != draw_tile.params.size.x || texture.height != draw_tile.params.size.y) {
/* Resolution divider is different from 1, force nearest interpolation. */
GPU_texture_bind_ex(texture.gpu_texture, GPU_SAMPLER_DEFAULT, 0);
GPU_texture_bind_ex(texture.gpu_texture, GPUSamplerState::default_sampler(), 0);
}
else if (zoomed_width - draw_tile.params.size.x > 0.5f ||
zoomed_height - draw_tile.params.size.y > 0.5f) {
GPU_texture_bind_ex(texture.gpu_texture, GPU_SAMPLER_DEFAULT, 0);
GPU_texture_bind_ex(texture.gpu_texture, GPUSamplerState::default_sampler(), 0);
}
else {
GPU_texture_bind_ex(texture.gpu_texture, GPU_SAMPLER_FILTER, 0);
GPU_texture_bind_ex(texture.gpu_texture, {GPU_SAMPLER_FILTERING_LINEAR}, 0);
}
/* Draw at the parameters for which the texture has been updated for. This allows to always draw

View File

@ -246,22 +246,25 @@ static void fill_generic_attribute(BL::Mesh &b_mesh,
if (polys_num == 0) {
return;
}
const MPoly *polys = static_cast<const MPoly *>(b_mesh.polygons[0].ptr.data);
const int *poly_offsets = static_cast<const int *>(b_mesh.polygons[0].ptr.data);
for (int i = 0; i < polys_num; i++) {
const MPoly &b_poly = polys[i];
for (int j = 0; j < b_poly.totloop; j++) {
*data = get_value_at_index(b_poly.loopstart + j);
const int poly_start = poly_offsets[i];
const int poly_size = poly_offsets[i + 1] - poly_start;
for (int j = 0; j < poly_size; j++) {
*data = get_value_at_index(poly_start + j);
data++;
}
}
}
else {
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
const int index = t.index() * 3;
BL::Array<int, 3> loops = t.loops();
data[index] = get_value_at_index(loops[0]);
data[index + 1] = get_value_at_index(loops[1]);
data[index + 2] = get_value_at_index(loops[2]);
const int tris_num = b_mesh.loop_triangles.length();
const MLoopTri *looptris = static_cast<const MLoopTri *>(
b_mesh.loop_triangles[0].ptr.data);
for (int i = 0; i < tris_num; i++) {
const MLoopTri &tri = looptris[i];
data[i * 3 + 0] = get_value_at_index(tri.tri[0]);
data[i * 3 + 1] = get_value_at_index(tri.tri[1]);
data[i * 3 + 2] = get_value_at_index(tri.tri[2]);
}
}
break;
@ -315,8 +318,11 @@ static void fill_generic_attribute(BL::Mesh &b_mesh,
}
}
else {
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
data[t.index()] = get_value_at_index(t.polygon_index());
const int tris_num = b_mesh.loop_triangles.length();
const MLoopTri *looptris = static_cast<const MLoopTri *>(
b_mesh.loop_triangles[0].ptr.data);
for (int i = 0; i < tris_num; i++) {
data[i] = get_value_at_index(looptris[i].poly);
}
}
break;
@ -533,6 +539,9 @@ static void attr_create_generic(Scene *scene,
static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
{
if (!b_mesh.uv_layers.empty()) {
const int tris_num = b_mesh.loop_triangles.length();
const MLoopTri *looptris = static_cast<const MLoopTri *>(b_mesh.loop_triangles[0].ptr.data);
for (BL::MeshUVLoopLayer &l : b_mesh.uv_layers) {
const bool active_render = l.active_render();
AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
@ -560,14 +569,13 @@ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
uv_attr = mesh->attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER);
}
const float(*b_uv_map)[2] = static_cast<const float(*)[2]>(l.uv[0].ptr.data);
float2 *fdata = uv_attr->data_float2();
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
int3 li = get_int3(t.loops());
fdata[0] = get_float2(l.data[li[0]].uv());
fdata[1] = get_float2(l.data[li[1]].uv());
fdata[2] = get_float2(l.data[li[2]].uv());
fdata += 3;
for (int i = 0; i < tris_num; i++) {
const MLoopTri &tri = looptris[i];
fdata[i * 3 + 0] = make_float2(b_uv_map[tri.tri[0]][0], b_uv_map[tri.tri[0]][1]);
fdata[i * 3 + 1] = make_float2(b_uv_map[tri.tri[1]][0], b_uv_map[tri.tri[1]][1]);
fdata[i * 3 + 2] = make_float2(b_uv_map[tri.tri[2]][0], b_uv_map[tri.tri[2]][1]);
}
}
@ -600,7 +608,7 @@ static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
if (polys_num == 0) {
return;
}
const MPoly *polys = static_cast<const MPoly *>(b_mesh.polygons[0].ptr.data);
const int *poly_offsets = static_cast<const int *>(b_mesh.polygons[0].ptr.data);
if (!b_mesh.uv_layers.empty()) {
BL::Mesh::uv_layers_iterator l;
@ -636,9 +644,10 @@ static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
float2 *fdata = uv_attr->data_float2();
for (int i = 0; i < polys_num; i++) {
const MPoly &b_poly = polys[i];
for (int j = 0; j < b_poly.totloop; j++) {
*(fdata++) = get_float2(l->data[b_poly.loopstart + j].uv());
const int poly_start = poly_offsets[i];
const int poly_size = poly_offsets[i + 1] - poly_start;
for (int j = 0; j < poly_size; j++) {
*(fdata++) = get_float2(l->data[poly_start + j].uv());
}
}
}
@ -910,10 +919,9 @@ static void attr_create_random_per_island(Scene *scene,
else {
const int polys_num = b_mesh.polygons.length();
if (polys_num != 0) {
const MPoly *polys = static_cast<const MPoly *>(b_mesh.polygons[0].ptr.data);
const int *poly_offsets = static_cast<const int *>(b_mesh.polygons[0].ptr.data);
for (int i = 0; i < polys_num; i++) {
const MPoly &b_poly = polys[i];
const int vert = corner_verts[b_poly.loopstart];
const int vert = corner_verts[poly_offsets[i]];
data[i] = hash_uint_to_float(vertices_sets.find(vert));
}
}
@ -1000,10 +1008,11 @@ static void create_mesh(Scene *scene,
numtris = numfaces;
}
else {
const MPoly *polys = static_cast<const MPoly *>(b_mesh.polygons[0].ptr.data);
const int *poly_offsets = static_cast<const int *>(b_mesh.polygons[0].ptr.data);
for (int i = 0; i < polys_num; i++) {
const MPoly &b_poly = polys[i];
numngons += (b_poly.totloop == 4) ? 0 : 1;
const int poly_start = poly_offsets[i];
const int poly_size = poly_offsets[i + 1] - poly_start;
numngons += (poly_size == 4) ? 0 : 1;
}
}
@ -1132,14 +1141,16 @@ static void create_mesh(Scene *scene,
std::copy(corner_verts, corner_verts + numcorners, subd_face_corners);
const MPoly *polys = static_cast<const MPoly *>(b_mesh.polygons[0].ptr.data);
const int *poly_offsets = static_cast<const int *>(b_mesh.polygons[0].ptr.data);
int ptex_offset = 0;
for (int i = 0; i < numfaces; i++) {
const MPoly &b_poly = polys[i];
subd_start_corner[i] = b_poly.loopstart;
subd_num_corners[i] = b_poly.totloop;
const int poly_start = poly_offsets[i];
const int poly_size = poly_offsets[i + 1] - poly_start;
subd_start_corner[i] = poly_start;
subd_num_corners[i] = poly_size;
subd_ptex_offset[i] = ptex_offset;
const int num_ptex = (b_poly.totloop == 4) ? 1 : b_poly.totloop;
const int num_ptex = (poly_size == 4) ? 1 : poly_size;
ptex_offset += num_ptex;
}

View File

@ -61,6 +61,11 @@ if(WITH_CYCLES_EMBREE)
list(APPEND LIB
${EMBREE_LIBRARIES}
)
if(EMBREE_SYCL_SUPPORT)
list(APPEND LIB
${SYCL_LIBRARIES}
)
endif()
endif()
cycles_add_library(cycles_bvh "${LIB}" ${SRC} ${SRC_HEADERS})

View File

@ -17,7 +17,11 @@
#ifdef WITH_EMBREE
# include <embree3/rtcore_geometry.h>
# if EMBREE_MAJOR_VERSION >= 4
# include <embree4/rtcore_geometry.h>
# else
# include <embree3/rtcore_geometry.h>
# endif
# include "bvh/embree.h"
@ -128,7 +132,11 @@ void BVHEmbree::build(Progress &progress, Stats *stats, RTCDevice rtc_device_)
scene = rtcNewScene(rtc_device);
const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |
(compact ? RTC_SCENE_FLAG_COMPACT : RTC_SCENE_FLAG_NONE) |
RTC_SCENE_FLAG_ROBUST;
RTC_SCENE_FLAG_ROBUST
# if EMBREE_MAJOR_VERSION >= 4
| RTC_SCENE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS
# endif
;
rtcSetSceneFlags(scene, scene_flags);
build_quality = dynamic ? RTC_BUILD_QUALITY_LOW :
(params.use_spatial_split ? RTC_BUILD_QUALITY_HIGH :
@ -226,6 +234,9 @@ void BVHEmbree::add_instance(Object *ob, int i)
rtcSetGeometryUserData(geom_id, (void *)instance_bvh->scene);
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
# if EMBREE_MAJOR_VERSION >= 4
rtcSetGeometryEnableFilterFunctionFromArguments(geom_id, true);
# endif
rtcCommitGeometry(geom_id);
rtcAttachGeometryByID(scene, geom_id, i * 2);
@ -267,9 +278,13 @@ void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
set_tri_vertex_buffer(geom_id, mesh, false);
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
# if EMBREE_MAJOR_VERSION >= 4
rtcSetGeometryEnableFilterFunctionFromArguments(geom_id, true);
# else
rtcSetGeometryOccludedFilterFunction(geom_id, kernel_embree_filter_occluded_func);
rtcSetGeometryIntersectFilterFunction(geom_id, kernel_embree_filter_intersection_func);
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
# endif
rtcCommitGeometry(geom_id);
rtcAttachGeometryByID(scene, geom_id, i * 2);
@ -494,9 +509,13 @@ void BVHEmbree::add_points(const Object *ob, const PointCloud *pointcloud, int i
set_point_vertex_buffer(geom_id, pointcloud, false);
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
# if EMBREE_MAJOR_VERSION >= 4
rtcSetGeometryEnableFilterFunctionFromArguments(geom_id, true);
# else
rtcSetGeometryIntersectFilterFunction(geom_id, kernel_embree_filter_func_backface_cull);
rtcSetGeometryOccludedFilterFunction(geom_id, kernel_embree_filter_occluded_func_backface_cull);
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
# endif
rtcCommitGeometry(geom_id);
rtcAttachGeometryByID(scene, geom_id, i * 2);
@ -553,6 +572,10 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
set_curve_vertex_buffer(geom_id, hair, false);
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
# if EMBREE_MAJOR_VERSION >= 4
rtcSetGeometryEnableFilterFunctionFromArguments(geom_id, true);
# else
if (hair->curve_shape == CURVE_RIBBON) {
rtcSetGeometryIntersectFilterFunction(geom_id, kernel_embree_filter_intersection_func);
rtcSetGeometryOccludedFilterFunction(geom_id, kernel_embree_filter_occluded_func);
@ -562,7 +585,7 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
rtcSetGeometryOccludedFilterFunction(geom_id,
kernel_embree_filter_occluded_func_backface_cull);
}
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
# endif
rtcCommitGeometry(geom_id);
rtcAttachGeometryByID(scene, geom_id, i * 2 + 1);

View File

@ -6,8 +6,13 @@
#ifdef WITH_EMBREE
# include <embree3/rtcore.h>
# include <embree3/rtcore_scene.h>
# if EMBREE_MAJOR_VERSION >= 4
# include <embree4/rtcore.h>
# include <embree4/rtcore_scene.h>
# else
# include <embree3/rtcore.h>
# include <embree3/rtcore_scene.h>
# endif
# include "bvh/bvh.h"
# include "bvh/params.h"

View File

@ -176,12 +176,10 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
else()
set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/../kernel/libcycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.so)
endif()
list(APPEND LIB ${cycles_kernel_oneapi_lib})
if(WIN32)
list(APPEND LIB debug ${SYCL_LIBRARY_DEBUG} optimized ${SYCL_LIBRARY})
else()
list(APPEND LIB ${SYCL_LIBRARY})
endif()
list(APPEND LIB
${cycles_kernel_oneapi_lib}
${SYCL_LIBRARIES}
)
list(APPEND SRC
${SRC_ONEAPI}
)

View File

@ -14,7 +14,11 @@
#endif
#ifdef WITH_EMBREE
# include <embree3/rtcore.h>
# if EMBREE_MAJOR_VERSION >= 4
# include <embree4/rtcore.h>
# else
# include <embree3/rtcore.h>
# endif
#endif
#include "device/cpu/kernel.h"

View File

@ -11,7 +11,11 @@
#endif
#ifdef WITH_EMBREE
# include <embree3/rtcore.h>
# if EMBREE_MAJOR_VERSION >= 4
# include <embree4/rtcore.h>
# else
# include <embree3/rtcore.h>
# endif
#endif
#include "device/cpu/kernel.h"

View File

@ -445,12 +445,10 @@ void MetalKernelPipeline::compile()
const std::string function_name = std::string("cycles_metal_") +
device_kernel_as_string(device_kernel);
NSString *entryPoint = [@(function_name.c_str()) copy];
NSError *error = NULL;
if (@available(macOS 11.0, *)) {
MTLFunctionDescriptor *func_desc = [MTLIntersectionFunctionDescriptor functionDescriptor];
func_desc.name = entryPoint;
func_desc.name = [@(function_name.c_str()) copy];
if (pso_type != PSO_GENERIC) {
func_desc.constantValues = GetConstantValues(&kernel_data_);
@ -462,8 +460,6 @@ void MetalKernelPipeline::compile()
function = [mtlLibrary newFunctionWithDescriptor:func_desc error:&error];
}
[entryPoint release];
if (function == nil) {
NSString *err = [error localizedDescription];
string errors = [err UTF8String];
@ -471,7 +467,7 @@ void MetalKernelPipeline::compile()
return;
}
function.label = [entryPoint copy];
function.label = [@(function_name.c_str()) copy];
if (use_metalrt) {
if (@available(macOS 11.0, *)) {

View File

@ -80,6 +80,12 @@ if(EXISTS ${USD_INCLUDE_DIR}/pxr/imaging/hgiGL)
list(APPEND SRC_HD_CYCLES_HEADERS display_driver.h)
endif()
# Silence warning from USD headers using deprecated TBB header.
add_definitions(
-D__TBB_show_deprecation_message_atomic_H
-D__TBB_show_deprecation_message_task_H
)
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})

View File

@ -4,6 +4,12 @@
#ifdef _WIN32
// Include first to avoid "NOGDI" definition set in Cycles headers
# ifndef NOMINMAX
# define NOMINMAX
# endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <Windows.h>
#endif

View File

@ -370,6 +370,16 @@ VtValue convertFromCyclesArray(const array<SrcType> &value)
return VtValue(convertedValue);
}
template<> VtValue convertFromCyclesArray<float2, GfVec2f>(const array<float2> &value)
{
VtVec2fArray convertedValue;
convertedValue.reserve(value.size());
for (const auto &element : value) {
convertedValue.push_back(GfVec2f(element.x, element.y));
}
return VtValue(convertedValue);
}
template<> VtValue convertFromCyclesArray<float3, GfVec3f>(const array<float3> &value)
{
VtVec3fArray convertedValue;

View File

@ -7,6 +7,7 @@
#include "device/device.h"
#include "device/memory.h"
#include "device/queue.h"
#include "integrator/pass_accessor_gpu.h"
#include "session/buffers.h"
#include "util/log.h"
#include "util/progress.h"
@ -105,4 +106,220 @@ Device *DenoiserGPU::ensure_denoiser_device(Progress *progress)
return denoiser_device;
}
DenoiserGPU::DenoiseContext::DenoiseContext(Device *device, const DenoiseTask &task)
: denoise_params(task.params),
render_buffers(task.render_buffers),
buffer_params(task.buffer_params),
guiding_buffer(device, "denoiser guiding passes buffer", true),
num_samples(task.num_samples)
{
num_input_passes = 1;
if (denoise_params.use_pass_albedo) {
num_input_passes += 1;
use_pass_albedo = true;
pass_denoising_albedo = buffer_params.get_pass_offset(PASS_DENOISING_ALBEDO);
if (denoise_params.use_pass_normal) {
num_input_passes += 1;
use_pass_normal = true;
pass_denoising_normal = buffer_params.get_pass_offset(PASS_DENOISING_NORMAL);
}
}
if (denoise_params.temporally_stable) {
prev_output.device_pointer = render_buffers->buffer.device_pointer;
prev_output.offset = buffer_params.get_pass_offset(PASS_DENOISING_PREVIOUS);
prev_output.stride = buffer_params.stride;
prev_output.pass_stride = buffer_params.pass_stride;
num_input_passes += 1;
use_pass_motion = true;
pass_motion = buffer_params.get_pass_offset(PASS_MOTION);
}
use_guiding_passes = (num_input_passes - 1) > 0;
if (use_guiding_passes) {
if (task.allow_inplace_modification) {
guiding_params.device_pointer = render_buffers->buffer.device_pointer;
guiding_params.pass_albedo = pass_denoising_albedo;
guiding_params.pass_normal = pass_denoising_normal;
guiding_params.pass_flow = pass_motion;
guiding_params.stride = buffer_params.stride;
guiding_params.pass_stride = buffer_params.pass_stride;
}
else {
guiding_params.pass_stride = 0;
if (use_pass_albedo) {
guiding_params.pass_albedo = guiding_params.pass_stride;
guiding_params.pass_stride += 3;
}
if (use_pass_normal) {
guiding_params.pass_normal = guiding_params.pass_stride;
guiding_params.pass_stride += 3;
}
if (use_pass_motion) {
guiding_params.pass_flow = guiding_params.pass_stride;
guiding_params.pass_stride += 2;
}
guiding_params.stride = buffer_params.width;
guiding_buffer.alloc_to_device(buffer_params.width * buffer_params.height *
guiding_params.pass_stride);
guiding_params.device_pointer = guiding_buffer.device_pointer;
}
}
pass_sample_count = buffer_params.get_pass_offset(PASS_SAMPLE_COUNT);
}
bool DenoiserGPU::denoise_filter_color_postprocess(const DenoiseContext &context,
const DenoisePass &pass)
{
const BufferParams &buffer_params = context.buffer_params;
const int work_size = buffer_params.width * buffer_params.height;
DeviceKernelArguments args(&context.render_buffers->buffer.device_pointer,
&buffer_params.full_x,
&buffer_params.full_y,
&buffer_params.width,
&buffer_params.height,
&buffer_params.offset,
&buffer_params.stride,
&buffer_params.pass_stride,
&context.num_samples,
&pass.noisy_offset,
&pass.denoised_offset,
&context.pass_sample_count,
&pass.num_components,
&pass.use_compositing);
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_COLOR_POSTPROCESS, work_size, args);
}
bool DenoiserGPU::denoise_filter_color_preprocess(const DenoiseContext &context,
const DenoisePass &pass)
{
const BufferParams &buffer_params = context.buffer_params;
const int work_size = buffer_params.width * buffer_params.height;
DeviceKernelArguments args(&context.render_buffers->buffer.device_pointer,
&buffer_params.full_x,
&buffer_params.full_y,
&buffer_params.width,
&buffer_params.height,
&buffer_params.offset,
&buffer_params.stride,
&buffer_params.pass_stride,
&pass.denoised_offset);
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_COLOR_PREPROCESS, work_size, args);
}
bool DenoiserGPU::denoise_filter_guiding_set_fake_albedo(const DenoiseContext &context)
{
const BufferParams &buffer_params = context.buffer_params;
const int work_size = buffer_params.width * buffer_params.height;
DeviceKernelArguments args(&context.guiding_params.device_pointer,
&context.guiding_params.pass_stride,
&context.guiding_params.pass_albedo,
&buffer_params.width,
&buffer_params.height);
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_GUIDING_SET_FAKE_ALBEDO, work_size, args);
}
void DenoiserGPU::denoise_color_read(const DenoiseContext &context, const DenoisePass &pass)
{
PassAccessor::PassAccessInfo pass_access_info;
pass_access_info.type = pass.type;
pass_access_info.mode = PassMode::NOISY;
pass_access_info.offset = pass.noisy_offset;
/* Denoiser operates on passes which are used to calculate the approximation, and is never used
* on the approximation. The latter is not even possible because OptiX does not support
* denoising of semi-transparent pixels. */
pass_access_info.use_approximate_shadow_catcher = false;
pass_access_info.use_approximate_shadow_catcher_background = false;
pass_access_info.show_active_pixels = false;
/* TODO(sergey): Consider adding support of actual exposure, to avoid clamping in extreme cases.
*/
const PassAccessorGPU pass_accessor(
denoiser_queue_.get(), pass_access_info, 1.0f, context.num_samples);
PassAccessor::Destination destination(pass_access_info.type);
destination.d_pixels = context.render_buffers->buffer.device_pointer +
pass.denoised_offset * sizeof(float);
destination.num_components = 3;
destination.pixel_stride = context.buffer_params.pass_stride;
BufferParams buffer_params = context.buffer_params;
buffer_params.window_x = 0;
buffer_params.window_y = 0;
buffer_params.window_width = buffer_params.width;
buffer_params.window_height = buffer_params.height;
pass_accessor.get_render_tile_pixels(context.render_buffers, buffer_params, destination);
}
void DenoiserGPU::denoise_pass(DenoiseContext &context, PassType pass_type)
{
const BufferParams &buffer_params = context.buffer_params;
const DenoisePass pass(pass_type, buffer_params);
if (pass.noisy_offset == PASS_UNUSED) {
return;
}
if (pass.denoised_offset == PASS_UNUSED) {
LOG(DFATAL) << "Missing denoised pass " << pass_type_as_string(pass_type);
return;
}
if (pass.use_denoising_albedo) {
if (context.albedo_replaced_with_fake) {
LOG(ERROR) << "Pass which requires albedo is denoised after fake albedo has been set.";
return;
}
}
else if (context.use_guiding_passes && !context.albedo_replaced_with_fake) {
context.albedo_replaced_with_fake = true;
if (!denoise_filter_guiding_set_fake_albedo(context)) {
LOG(ERROR) << "Error replacing real albedo with the fake one.";
return;
}
}
/* Read and preprocess noisy color input pass. */
denoise_color_read(context, pass);
if (!denoise_filter_color_preprocess(context, pass)) {
LOG(ERROR) << "Error converting denoising passes to RGB buffer.";
return;
}
if (!denoise_run(context, pass)) {
LOG(ERROR) << "Error running denoiser.";
return;
}
/* Store result in the combined pass of the render buffer.
*
* This will scale the denoiser result up to match the number of, possibly per-pixel, samples. */
if (!denoise_filter_color_postprocess(context, pass)) {
LOG(ERROR) << "Error copying denoiser result to the denoised pass.";
return;
}
denoiser_queue_->synchronize();
}
CCL_NAMESPACE_END

View File

@ -21,6 +21,9 @@ class DenoiserGPU : public Denoiser {
bool allow_inplace_modification) override;
protected:
class DenoisePass;
class DenoiseContext;
/* All the parameters needed to perform buffer denoising on a device.
* Is not really a task in its canonical terms (as in, is not an asynchronous running task). Is
* more like a wrapper for all the arguments and parameters needed to perform denoising. Is a
@ -41,12 +44,105 @@ class DenoiserGPU : public Denoiser {
bool allow_inplace_modification;
};
/* Read input color pass from the render buffer into the memory which corresponds to the noisy
* input within the given context. Pixels are scaled to the number of samples, but are not
* preprocessed yet. */
void denoise_color_read(const DenoiseContext &context, const DenoisePass &pass);
/* Run corresponding filter kernels, preparing data for the denoiser or copying data from the
* denoiser result to the render buffer. */
bool denoise_filter_color_preprocess(const DenoiseContext &context, const DenoisePass &pass);
bool denoise_filter_color_postprocess(const DenoiseContext &context, const DenoisePass &pass);
bool denoise_filter_guiding_set_fake_albedo(const DenoiseContext &context);
void denoise_pass(DenoiseContext &context, PassType pass_type);
/* Returns true if task is fully handled. */
virtual bool denoise_buffer(const DenoiseTask & /*task*/) = 0;
virtual bool denoise_run(const DenoiseContext &context, const DenoisePass &pass) = 0;
virtual Device *ensure_denoiser_device(Progress *progress) override;
unique_ptr<DeviceQueue> denoiser_queue_;
class DenoisePass {
public:
DenoisePass(const PassType type, const BufferParams &buffer_params) : type(type)
{
noisy_offset = buffer_params.get_pass_offset(type, PassMode::NOISY);
denoised_offset = buffer_params.get_pass_offset(type, PassMode::DENOISED);
const PassInfo pass_info = Pass::get_info(type);
num_components = pass_info.num_components;
use_compositing = pass_info.use_compositing;
use_denoising_albedo = pass_info.use_denoising_albedo;
}
PassType type;
int noisy_offset;
int denoised_offset;
int num_components;
bool use_compositing;
bool use_denoising_albedo;
};
class DenoiseContext {
public:
explicit DenoiseContext(Device *device, const DenoiseTask &task);
const DenoiseParams &denoise_params;
RenderBuffers *render_buffers = nullptr;
const BufferParams &buffer_params;
/* Previous output. */
struct {
device_ptr device_pointer = 0;
int offset = PASS_UNUSED;
int stride = -1;
int pass_stride = -1;
} prev_output;
/* Device-side storage of the guiding passes. */
device_only_memory<float> guiding_buffer;
struct {
device_ptr device_pointer = 0;
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_albedo = PASS_UNUSED;
int pass_normal = PASS_UNUSED;
int pass_flow = PASS_UNUSED;
int stride = -1;
int pass_stride = -1;
} guiding_params;
/* Number of input passes. Including the color and extra auxiliary passes. */
int num_input_passes = 0;
bool use_guiding_passes = false;
bool use_pass_albedo = false;
bool use_pass_normal = false;
bool use_pass_motion = false;
int num_samples = 0;
int pass_sample_count = PASS_UNUSED;
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_denoising_albedo = PASS_UNUSED;
int pass_denoising_normal = PASS_UNUSED;
int pass_motion = PASS_UNUSED;
/* For passes which don't need albedo channel for denoising we replace the actual albedo with
* the (0.5, 0.5, 0.5). This flag indicates that the real albedo pass has been replaced with
* the fake values and denoising of passes which do need albedo can no longer happen. */
bool albedo_replaced_with_fake = false;
};
};
CCL_NAMESPACE_END

View File

@ -218,154 +218,6 @@ uint OptiXDenoiser::get_device_type_mask() const
return DEVICE_MASK_OPTIX;
}
class OptiXDenoiser::DenoiseContext {
public:
explicit DenoiseContext(OptiXDevice *device, const DenoiseTask &task)
: denoise_params(task.params),
render_buffers(task.render_buffers),
buffer_params(task.buffer_params),
guiding_buffer(device, "denoiser guiding passes buffer", true),
num_samples(task.num_samples)
{
num_input_passes = 1;
if (denoise_params.use_pass_albedo) {
num_input_passes += 1;
use_pass_albedo = true;
pass_denoising_albedo = buffer_params.get_pass_offset(PASS_DENOISING_ALBEDO);
if (denoise_params.use_pass_normal) {
num_input_passes += 1;
use_pass_normal = true;
pass_denoising_normal = buffer_params.get_pass_offset(PASS_DENOISING_NORMAL);
}
}
if (denoise_params.temporally_stable) {
prev_output.device_pointer = render_buffers->buffer.device_pointer;
prev_output.offset = buffer_params.get_pass_offset(PASS_DENOISING_PREVIOUS);
prev_output.stride = buffer_params.stride;
prev_output.pass_stride = buffer_params.pass_stride;
num_input_passes += 1;
use_pass_motion = true;
pass_motion = buffer_params.get_pass_offset(PASS_MOTION);
}
use_guiding_passes = (num_input_passes - 1) > 0;
if (use_guiding_passes) {
if (task.allow_inplace_modification) {
guiding_params.device_pointer = render_buffers->buffer.device_pointer;
guiding_params.pass_albedo = pass_denoising_albedo;
guiding_params.pass_normal = pass_denoising_normal;
guiding_params.pass_flow = pass_motion;
guiding_params.stride = buffer_params.stride;
guiding_params.pass_stride = buffer_params.pass_stride;
}
else {
guiding_params.pass_stride = 0;
if (use_pass_albedo) {
guiding_params.pass_albedo = guiding_params.pass_stride;
guiding_params.pass_stride += 3;
}
if (use_pass_normal) {
guiding_params.pass_normal = guiding_params.pass_stride;
guiding_params.pass_stride += 3;
}
if (use_pass_motion) {
guiding_params.pass_flow = guiding_params.pass_stride;
guiding_params.pass_stride += 2;
}
guiding_params.stride = buffer_params.width;
guiding_buffer.alloc_to_device(buffer_params.width * buffer_params.height *
guiding_params.pass_stride);
guiding_params.device_pointer = guiding_buffer.device_pointer;
}
}
pass_sample_count = buffer_params.get_pass_offset(PASS_SAMPLE_COUNT);
}
const DenoiseParams &denoise_params;
RenderBuffers *render_buffers = nullptr;
const BufferParams &buffer_params;
/* Previous output. */
struct {
device_ptr device_pointer = 0;
int offset = PASS_UNUSED;
int stride = -1;
int pass_stride = -1;
} prev_output;
/* Device-side storage of the guiding passes. */
device_only_memory<float> guiding_buffer;
struct {
device_ptr device_pointer = 0;
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_albedo = PASS_UNUSED;
int pass_normal = PASS_UNUSED;
int pass_flow = PASS_UNUSED;
int stride = -1;
int pass_stride = -1;
} guiding_params;
/* Number of input passes. Including the color and extra auxiliary passes. */
int num_input_passes = 0;
bool use_guiding_passes = false;
bool use_pass_albedo = false;
bool use_pass_normal = false;
bool use_pass_motion = false;
int num_samples = 0;
int pass_sample_count = PASS_UNUSED;
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_denoising_albedo = PASS_UNUSED;
int pass_denoising_normal = PASS_UNUSED;
int pass_motion = PASS_UNUSED;
/* For passes which don't need albedo channel for denoising we replace the actual albedo with
* the (0.5, 0.5, 0.5). This flag indicates that the real albedo pass has been replaced with
* the fake values and denoising of passes which do need albedo can no longer happen. */
bool albedo_replaced_with_fake = false;
};
class OptiXDenoiser::DenoisePass {
public:
DenoisePass(const PassType type, const BufferParams &buffer_params) : type(type)
{
noisy_offset = buffer_params.get_pass_offset(type, PassMode::NOISY);
denoised_offset = buffer_params.get_pass_offset(type, PassMode::DENOISED);
const PassInfo pass_info = Pass::get_info(type);
num_components = pass_info.num_components;
use_compositing = pass_info.use_compositing;
use_denoising_albedo = pass_info.use_denoising_albedo;
}
PassType type;
int noisy_offset;
int denoised_offset;
int num_components;
bool use_compositing;
bool use_denoising_albedo;
};
bool OptiXDenoiser::denoise_buffer(const DenoiseTask &task)
{
OptiXDevice *const optix_device = static_cast<OptiXDevice *>(denoiser_device_);
@ -421,151 +273,6 @@ bool OptiXDenoiser::denoise_filter_guiding_preprocess(const DenoiseContext &cont
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_GUIDING_PREPROCESS, work_size, args);
}
bool OptiXDenoiser::denoise_filter_guiding_set_fake_albedo(const DenoiseContext &context)
{
const BufferParams &buffer_params = context.buffer_params;
const int work_size = buffer_params.width * buffer_params.height;
DeviceKernelArguments args(&context.guiding_params.device_pointer,
&context.guiding_params.pass_stride,
&context.guiding_params.pass_albedo,
&buffer_params.width,
&buffer_params.height);
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_GUIDING_SET_FAKE_ALBEDO, work_size, args);
}
void OptiXDenoiser::denoise_pass(DenoiseContext &context, PassType pass_type)
{
const BufferParams &buffer_params = context.buffer_params;
const DenoisePass pass(pass_type, buffer_params);
if (pass.noisy_offset == PASS_UNUSED) {
return;
}
if (pass.denoised_offset == PASS_UNUSED) {
LOG(DFATAL) << "Missing denoised pass " << pass_type_as_string(pass_type);
return;
}
if (pass.use_denoising_albedo) {
if (context.albedo_replaced_with_fake) {
LOG(ERROR) << "Pass which requires albedo is denoised after fake albedo has been set.";
return;
}
}
else if (context.use_guiding_passes && !context.albedo_replaced_with_fake) {
context.albedo_replaced_with_fake = true;
if (!denoise_filter_guiding_set_fake_albedo(context)) {
LOG(ERROR) << "Error replacing real albedo with the fake one.";
return;
}
}
/* Read and preprocess noisy color input pass. */
denoise_color_read(context, pass);
if (!denoise_filter_color_preprocess(context, pass)) {
LOG(ERROR) << "Error converting denoising passes to RGB buffer.";
return;
}
if (!denoise_run(context, pass)) {
LOG(ERROR) << "Error running OptiX denoiser.";
return;
}
/* Store result in the combined pass of the render buffer.
*
* This will scale the denoiser result up to match the number of, possibly per-pixel, samples. */
if (!denoise_filter_color_postprocess(context, pass)) {
LOG(ERROR) << "Error copying denoiser result to the denoised pass.";
return;
}
denoiser_queue_->synchronize();
}
void OptiXDenoiser::denoise_color_read(const DenoiseContext &context, const DenoisePass &pass)
{
PassAccessor::PassAccessInfo pass_access_info;
pass_access_info.type = pass.type;
pass_access_info.mode = PassMode::NOISY;
pass_access_info.offset = pass.noisy_offset;
/* Denoiser operates on passes which are used to calculate the approximation, and is never used
* on the approximation. The latter is not even possible because OptiX does not support
* denoising of semi-transparent pixels. */
pass_access_info.use_approximate_shadow_catcher = false;
pass_access_info.use_approximate_shadow_catcher_background = false;
pass_access_info.show_active_pixels = false;
/* TODO(sergey): Consider adding support of actual exposure, to avoid clamping in extreme cases.
*/
const PassAccessorGPU pass_accessor(
denoiser_queue_.get(), pass_access_info, 1.0f, context.num_samples);
PassAccessor::Destination destination(pass_access_info.type);
destination.d_pixels = context.render_buffers->buffer.device_pointer +
pass.denoised_offset * sizeof(float);
destination.num_components = 3;
destination.pixel_stride = context.buffer_params.pass_stride;
BufferParams buffer_params = context.buffer_params;
buffer_params.window_x = 0;
buffer_params.window_y = 0;
buffer_params.window_width = buffer_params.width;
buffer_params.window_height = buffer_params.height;
pass_accessor.get_render_tile_pixels(context.render_buffers, buffer_params, destination);
}
bool OptiXDenoiser::denoise_filter_color_preprocess(const DenoiseContext &context,
const DenoisePass &pass)
{
const BufferParams &buffer_params = context.buffer_params;
const int work_size = buffer_params.width * buffer_params.height;
DeviceKernelArguments args(&context.render_buffers->buffer.device_pointer,
&buffer_params.full_x,
&buffer_params.full_y,
&buffer_params.width,
&buffer_params.height,
&buffer_params.offset,
&buffer_params.stride,
&buffer_params.pass_stride,
&pass.denoised_offset);
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_COLOR_PREPROCESS, work_size, args);
}
bool OptiXDenoiser::denoise_filter_color_postprocess(const DenoiseContext &context,
const DenoisePass &pass)
{
const BufferParams &buffer_params = context.buffer_params;
const int work_size = buffer_params.width * buffer_params.height;
DeviceKernelArguments args(&context.render_buffers->buffer.device_pointer,
&buffer_params.full_x,
&buffer_params.full_y,
&buffer_params.width,
&buffer_params.height,
&buffer_params.offset,
&buffer_params.stride,
&buffer_params.pass_stride,
&context.num_samples,
&pass.noisy_offset,
&pass.denoised_offset,
&context.pass_sample_count,
&pass.num_components,
&pass.use_compositing);
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_COLOR_POSTPROCESS, work_size, args);
}
bool OptiXDenoiser::denoise_ensure(DenoiseContext &context)
{
if (!denoise_create_if_needed(context)) {

View File

@ -21,9 +21,6 @@ class OptiXDenoiser : public DenoiserGPU {
virtual uint get_device_type_mask() const override;
private:
class DenoiseContext;
class DenoisePass;
virtual bool denoise_buffer(const DenoiseTask &task) override;
/* Read guiding passes from the render buffers, preprocess them in a way which is expected by
@ -36,19 +33,6 @@ class OptiXDenoiser : public DenoiserGPU {
/* Set fake albedo pixels in the albedo guiding pass storage.
* After this point only passes which do not need albedo for denoising can be processed. */
bool denoise_filter_guiding_set_fake_albedo(const DenoiseContext &context);
void denoise_pass(DenoiseContext &context, PassType pass_type);
/* Read input color pass from the render buffer into the memory which corresponds to the noisy
* input within the given context. Pixels are scaled to the number of samples, but are not
* preprocessed yet. */
void denoise_color_read(const DenoiseContext &context, const DenoisePass &pass);
/* Run corresponding filter kernels, preparing data for the denoiser or copying data from the
* denoiser result to the render buffer. */
bool denoise_filter_color_preprocess(const DenoiseContext &context, const DenoisePass &pass);
bool denoise_filter_color_postprocess(const DenoiseContext &context, const DenoisePass &pass);
/* Make sure the OptiX denoiser is created and configured. */
bool denoise_ensure(DenoiseContext &context);
@ -61,7 +45,7 @@ class OptiXDenoiser : public DenoiserGPU {
bool denoise_configure_if_needed(DenoiseContext &context);
/* Run configured denoiser. */
bool denoise_run(const DenoiseContext &context, const DenoisePass &pass);
bool denoise_run(const DenoiseContext &context, const DenoisePass &pass) override;
OptixDenoiser optix_denoiser_ = nullptr;

View File

@ -362,7 +362,7 @@ void PathTraceWorkCPU::guiding_push_sample_data_to_global_storage(
# endif
# ifdef WITH_CYCLES_DEBUG
/* Check if the training/radiance samples generated py the path segment storage are valid.*/
/* Check if the training/radiance samples generated by the path segment storage are valid. */
if (VLOG_WORK_IS_ON) {
const bool validSamples = kg->opgl_path_segment_storage->ValidateSamples();
if (!validSamples) {

View File

@ -5,8 +5,13 @@
#pragma once
#include <embree3/rtcore_ray.h>
#include <embree3/rtcore_scene.h>
#if EMBREE_MAJOR_VERSION >= 4
# include <embree4/rtcore_ray.h>
# include <embree4/rtcore_scene.h>
#else
# include <embree3/rtcore_ray.h>
# include <embree3/rtcore_scene.h>
#endif
#include "kernel/device/cpu/compat.h"
#include "kernel/device/cpu/globals.h"
@ -28,11 +33,84 @@ using numhit_t = uint8_t;
using numhit_t = uint32_t;
#endif
#define CYCLES_EMBREE_USED_FEATURES \
(RTCFeatureFlags)(RTC_FEATURE_FLAG_TRIANGLE | RTC_FEATURE_FLAG_INSTANCE | \
RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS | RTC_FEATURE_FLAG_POINT | \
RTC_FEATURE_FLAG_MOTION_BLUR | RTC_FEATURE_FLAG_ROUND_CATMULL_ROM_CURVE | \
RTC_FEATURE_FLAG_FLAT_CATMULL_ROM_CURVE)
#define EMBREE_IS_HAIR(x) (x & 1)
#if EMBREE_MAJOR_VERSION < 4
# define rtcGetGeometryUserDataFromScene(scene, id) \
(rtcGetGeometryUserData(rtcGetGeometry(scene, id)))
#endif
/* Intersection context. */
struct CCLIntersectContext {
struct CCLFirstHitContext
#if EMBREE_MAJOR_VERSION >= 4
: public RTCRayQueryContext
#endif
{
KernelGlobals kg;
/* For avoiding self intersections */
const Ray *ray;
};
struct CCLShadowContext
#if EMBREE_MAJOR_VERSION >= 4
: public RTCRayQueryContext
#endif
{
#if EMBREE_MAJOR_VERSION >= 4
KernelGlobals kg;
const Ray *ray;
#endif
IntegratorShadowState isect_s;
float throughput;
bool opaque_hit;
numhit_t max_hits;
numhit_t num_hits;
numhit_t num_recorded_hits;
};
struct CCLLocalContext
#if EMBREE_MAJOR_VERSION >= 4
: public RTCRayQueryContext
#endif
{
#if EMBREE_MAJOR_VERSION >= 4
KernelGlobals kg;
const Ray *ray;
numhit_t max_hits;
#endif
int local_object_id;
LocalIntersection *local_isect;
uint *lcg_state;
bool is_sss;
};
struct CCLVolumeContext
#if EMBREE_MAJOR_VERSION >= 4
: public RTCRayQueryContext
#endif
{
#if EMBREE_MAJOR_VERSION >= 4
KernelGlobals kg;
const Ray *ray;
numhit_t max_hits;
numhit_t num_hits;
#endif
Intersection *vol_isect;
};
#if EMBREE_MAJOR_VERSION < 4
struct CCLIntersectContext : public RTCIntersectContext,
public CCLFirstHitContext,
public CCLShadowContext,
public CCLLocalContext,
public CCLVolumeContext {
typedef enum {
RAY_REGULAR = 0,
RAY_SHADOW_ALL = 1,
@ -41,28 +119,8 @@ struct CCLIntersectContext {
RAY_VOLUME_ALL = 4,
} RayType;
KernelGlobals kg;
RayType type;
/* For avoiding self intersections */
const Ray *ray;
/* for shadow rays */
IntegratorShadowState isect_s;
numhit_t max_hits;
numhit_t num_hits;
numhit_t num_recorded_hits;
float throughput;
bool opaque_hit;
/* for SSS Rays: */
LocalIntersection *local_isect;
int local_object_id;
uint *lcg_state;
/* for Volume */
Intersection *vol_isect;
CCLIntersectContext(KernelGlobals kg_, RayType type_)
{
kg = kg_;
@ -79,17 +137,7 @@ struct CCLIntersectContext {
lcg_state = NULL;
}
};
class IntersectContext {
public:
IntersectContext(CCLIntersectContext *ctx)
{
rtcInitIntersectContext(&context);
userRayExt = ctx;
}
RTCIntersectContext context;
CCLIntersectContext *userRayExt;
};
#endif
/* Utilities. */
@ -173,13 +221,12 @@ ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg,
{
intptr_t prim_offset;
if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) {
RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
rtcGetGeometry(kernel_data.device_bvh, hit->instID[0]));
prim_offset = intptr_t(rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID)));
RTCScene inst_scene = (RTCScene)rtcGetGeometryUserDataFromScene(kernel_data.device_bvh,
hit->instID[0]);
prim_offset = intptr_t(rtcGetGeometryUserDataFromScene(inst_scene, hit->geomID));
}
else {
prim_offset = intptr_t(
rtcGetGeometryUserData(rtcGetGeometry(kernel_data.device_bvh, hit->geomID)));
prim_offset = intptr_t(rtcGetGeometryUserDataFromScene(kernel_data.device_bvh, hit->geomID));
}
kernel_embree_convert_hit(kg, ray, hit, isect, prim_offset);
}
@ -211,7 +258,11 @@ ccl_device void kernel_embree_filter_intersection_func(const RTCFilterFunctionNA
assert(args->N == 1);
RTCHit *hit = (RTCHit *)args->hit;
CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
#if EMBREE_MAJOR_VERSION >= 4
CCLFirstHitContext *ctx = (CCLFirstHitContext *)(args->context);
#else
CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
#endif
const KernelGlobalsCPU *kg = ctx->kg;
const Ray *cray = ctx->ray;
@ -226,205 +277,257 @@ ccl_device void kernel_embree_filter_intersection_func(const RTCFilterFunctionNA
* as well as filtering for volume objects happen here.
* Cycles' own BVH does that directly inside the traversal calls.
*/
ccl_device void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArguments *args)
ccl_device void kernel_embree_filter_occluded_shadow_all_func(
const RTCFilterFunctionNArguments *args)
{
/* Current implementation in Cycles assumes only single-ray intersection queries. */
assert(args->N == 1);
RTCRay *ray = (RTCRay *)args->ray;
RTCHit *hit = (RTCHit *)args->hit;
CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
#if EMBREE_MAJOR_VERSION >= 4
CCLShadowContext *ctx = (CCLShadowContext *)(args->context);
#else
CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
#endif
const KernelGlobalsCPU *kg = ctx->kg;
const Ray *cray = ctx->ray;
Intersection current_isect;
kernel_embree_convert_hit(
kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
if (intersection_skip_self_shadow(cray->self, current_isect.object, current_isect.prim)) {
*args->valid = 0;
return;
}
/* If no transparent shadows or max number of hits exceeded, all light is blocked. */
const int flags = intersection_get_shader_flags(kg, current_isect.prim, current_isect.type);
if (!(flags & (SD_HAS_TRANSPARENT_SHADOW)) || ctx->num_hits >= ctx->max_hits) {
ctx->opaque_hit = true;
return;
}
++ctx->num_hits;
/* Always use baked shadow transparency for curves. */
if (current_isect.type & PRIMITIVE_CURVE) {
ctx->throughput *= intersection_curve_shadow_transparency(
kg, current_isect.object, current_isect.prim, current_isect.type, current_isect.u);
if (ctx->throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
ctx->opaque_hit = true;
return;
}
else {
*args->valid = 0;
return;
}
}
/* Test if we need to record this transparent intersection. */
const numhit_t max_record_hits = min(ctx->max_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
if (ctx->num_recorded_hits < max_record_hits) {
/* If maximum number of hits was reached, replace the intersection with the
* highest distance. We want to find the N closest intersections. */
const numhit_t num_recorded_hits = min(ctx->num_recorded_hits, max_record_hits);
numhit_t isect_index = num_recorded_hits;
if (num_recorded_hits + 1 >= max_record_hits) {
float max_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, 0, t);
numhit_t max_recorded_hit = numhit_t(0);
for (numhit_t i = numhit_t(1); i < num_recorded_hits; ++i) {
const float isect_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, i, t);
if (isect_t > max_t) {
max_recorded_hit = i;
max_t = isect_t;
}
}
if (num_recorded_hits >= max_record_hits) {
isect_index = max_recorded_hit;
}
/* Limit the ray distance and stop counting hits beyond this. */
ray->tfar = max(current_isect.t, max_t);
}
integrator_state_write_shadow_isect(ctx->isect_s, &current_isect, isect_index);
}
/* Always increase the number of recorded hits, even beyond the maximum,
* so that we can detect this and trace another ray if needed. */
++ctx->num_recorded_hits;
/* This tells Embree to continue tracing. */
*args->valid = 0;
}
ccl_device_forceinline void kernel_embree_filter_occluded_local_func(
const RTCFilterFunctionNArguments *args)
{
/* Current implementation in Cycles assumes only single-ray intersection queries. */
assert(args->N == 1);
const RTCRay *ray = (RTCRay *)args->ray;
RTCHit *hit = (RTCHit *)args->hit;
#if EMBREE_MAJOR_VERSION >= 4
CCLLocalContext *ctx = (CCLLocalContext *)(args->context);
#else
CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
#endif
const KernelGlobalsCPU *kg = ctx->kg;
const Ray *cray = ctx->ray;
/* Check if it's hitting the correct object. */
Intersection current_isect;
if (ctx->is_sss) {
kernel_embree_convert_sss_hit(kg,
ray,
hit,
&current_isect,
ctx->local_object_id,
reinterpret_cast<intptr_t>(args->geometryUserPtr));
}
else {
kernel_embree_convert_hit(
kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
if (ctx->local_object_id != current_isect.object) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
return;
}
}
if (intersection_skip_self_local(cray->self, current_isect.prim)) {
*args->valid = 0;
return;
}
/* No intersection information requested, just return a hit. */
if (ctx->max_hits == 0) {
return;
}
/* Ignore curves. */
if (EMBREE_IS_HAIR(hit->geomID)) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
return;
}
LocalIntersection *local_isect = ctx->local_isect;
int hit_idx = 0;
if (ctx->lcg_state) {
/* See triangle_intersect_subsurface() for the native equivalent. */
for (int i = min((int)ctx->max_hits, local_isect->num_hits) - 1; i >= 0; --i) {
if (local_isect->hits[i].t == ray->tfar) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
return;
}
}
local_isect->num_hits++;
if (local_isect->num_hits <= ctx->max_hits) {
hit_idx = local_isect->num_hits - 1;
}
else {
/* reservoir sampling: if we are at the maximum number of
* hits, randomly replace element or skip it */
hit_idx = lcg_step_uint(ctx->lcg_state) % local_isect->num_hits;
if (hit_idx >= ctx->max_hits) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
return;
}
}
}
else {
/* Record closest intersection only. */
if (local_isect->num_hits && current_isect.t > local_isect->hits[0].t) {
*args->valid = 0;
return;
}
local_isect->num_hits = 1;
}
/* record intersection */
local_isect->hits[hit_idx] = current_isect;
local_isect->Ng[hit_idx] = normalize(make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z));
/* This tells Embree to continue tracing. */
*args->valid = 0;
}
ccl_device_forceinline void kernel_embree_filter_occluded_volume_all_func(
const RTCFilterFunctionNArguments *args)
{
/* Current implementation in Cycles assumes only single-ray intersection queries. */
assert(args->N == 1);
const RTCRay *ray = (RTCRay *)args->ray;
RTCHit *hit = (RTCHit *)args->hit;
#if EMBREE_MAJOR_VERSION >= 4
CCLVolumeContext *ctx = (CCLVolumeContext *)(args->context);
#else
CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
#endif
const KernelGlobalsCPU *kg = ctx->kg;
const Ray *cray = ctx->ray;
/* Append the intersection to the end of the array. */
if (ctx->num_hits < ctx->max_hits) {
Intersection current_isect;
kernel_embree_convert_hit(
kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
if (intersection_skip_self(cray->self, current_isect.object, current_isect.prim)) {
*args->valid = 0;
return;
}
Intersection *isect = &ctx->vol_isect[ctx->num_hits];
++ctx->num_hits;
*isect = current_isect;
/* Only primitives from volume object. */
uint tri_object = isect->object;
int object_flag = kernel_data_fetch(object_flag, tri_object);
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
--ctx->num_hits;
}
/* This tells Embree to continue tracing. */
*args->valid = 0;
}
}
#if EMBREE_MAJOR_VERSION < 4
ccl_device_forceinline void kernel_embree_filter_occluded_func(
const RTCFilterFunctionNArguments *args)
{
/* Current implementation in Cycles assumes only single-ray intersection queries. */
assert(args->N == 1);
CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
switch (ctx->type) {
case CCLIntersectContext::RAY_SHADOW_ALL: {
Intersection current_isect;
kernel_embree_convert_hit(
kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
if (intersection_skip_self_shadow(cray->self, current_isect.object, current_isect.prim)) {
*args->valid = 0;
return;
}
/* If no transparent shadows or max number of hits exceeded, all light is blocked. */
const int flags = intersection_get_shader_flags(kg, current_isect.prim, current_isect.type);
if (!(flags & (SD_HAS_TRANSPARENT_SHADOW)) || ctx->num_hits >= ctx->max_hits) {
ctx->opaque_hit = true;
return;
}
++ctx->num_hits;
/* Always use baked shadow transparency for curves. */
if (current_isect.type & PRIMITIVE_CURVE) {
ctx->throughput *= intersection_curve_shadow_transparency(
kg, current_isect.object, current_isect.prim, current_isect.type, current_isect.u);
if (ctx->throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
ctx->opaque_hit = true;
return;
}
else {
*args->valid = 0;
return;
}
}
/* Test if we need to record this transparent intersection. */
const numhit_t max_record_hits = min(ctx->max_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
if (ctx->num_recorded_hits < max_record_hits) {
/* If maximum number of hits was reached, replace the intersection with the
* highest distance. We want to find the N closest intersections. */
const numhit_t num_recorded_hits = min(ctx->num_recorded_hits, max_record_hits);
numhit_t isect_index = num_recorded_hits;
if (num_recorded_hits + 1 >= max_record_hits) {
float max_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, 0, t);
numhit_t max_recorded_hit = numhit_t(0);
for (numhit_t i = numhit_t(1); i < num_recorded_hits; ++i) {
const float isect_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, i, t);
if (isect_t > max_t) {
max_recorded_hit = i;
max_t = isect_t;
}
}
if (num_recorded_hits >= max_record_hits) {
isect_index = max_recorded_hit;
}
/* Limit the ray distance and stop counting hits beyond this. */
ray->tfar = max(current_isect.t, max_t);
}
integrator_state_write_shadow_isect(ctx->isect_s, &current_isect, isect_index);
}
/* Always increase the number of recorded hits, even beyond the maximum,
* so that we can detect this and trace another ray if needed. */
++ctx->num_recorded_hits;
/* This tells Embree to continue tracing. */
*args->valid = 0;
case CCLIntersectContext::RAY_SHADOW_ALL:
kernel_embree_filter_occluded_shadow_all_func(args);
break;
}
case CCLIntersectContext::RAY_LOCAL:
case CCLIntersectContext::RAY_SSS: {
/* Check if it's hitting the correct object. */
Intersection current_isect;
if (ctx->type == CCLIntersectContext::RAY_SSS) {
kernel_embree_convert_sss_hit(kg,
ray,
hit,
&current_isect,
ctx->local_object_id,
reinterpret_cast<intptr_t>(args->geometryUserPtr));
}
else {
kernel_embree_convert_hit(
kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
if (ctx->local_object_id != current_isect.object) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
break;
}
}
if (intersection_skip_self_local(cray->self, current_isect.prim)) {
*args->valid = 0;
return;
}
/* No intersection information requested, just return a hit. */
if (ctx->max_hits == 0) {
break;
}
/* Ignore curves. */
if (EMBREE_IS_HAIR(hit->geomID)) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
break;
}
LocalIntersection *local_isect = ctx->local_isect;
int hit_idx = 0;
if (ctx->lcg_state) {
/* See triangle_intersect_subsurface() for the native equivalent. */
for (int i = min((int)ctx->max_hits, local_isect->num_hits) - 1; i >= 0; --i) {
if (local_isect->hits[i].t == ray->tfar) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
return;
}
}
local_isect->num_hits++;
if (local_isect->num_hits <= ctx->max_hits) {
hit_idx = local_isect->num_hits - 1;
}
else {
/* reservoir sampling: if we are at the maximum number of
* hits, randomly replace element or skip it */
hit_idx = lcg_step_uint(ctx->lcg_state) % local_isect->num_hits;
if (hit_idx >= ctx->max_hits) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
return;
}
}
}
else {
/* Record closest intersection only. */
if (local_isect->num_hits && current_isect.t > local_isect->hits[0].t) {
*args->valid = 0;
return;
}
local_isect->num_hits = 1;
}
/* record intersection */
local_isect->hits[hit_idx] = current_isect;
local_isect->Ng[hit_idx] = normalize(make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z));
/* This tells Embree to continue tracing. */
*args->valid = 0;
case CCLIntersectContext::RAY_SSS:
kernel_embree_filter_occluded_local_func(args);
break;
}
case CCLIntersectContext::RAY_VOLUME_ALL: {
/* Append the intersection to the end of the array. */
if (ctx->num_hits < ctx->max_hits) {
Intersection current_isect;
kernel_embree_convert_hit(
kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
if (intersection_skip_self(cray->self, current_isect.object, current_isect.prim)) {
*args->valid = 0;
return;
}
Intersection *isect = &ctx->vol_isect[ctx->num_hits];
++ctx->num_hits;
*isect = current_isect;
/* Only primitives from volume object. */
uint tri_object = isect->object;
int object_flag = kernel_data_fetch(object_flag, tri_object);
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
--ctx->num_hits;
}
/* This tells Embree to continue tracing. */
*args->valid = 0;
}
case CCLIntersectContext::RAY_VOLUME_ALL:
kernel_embree_filter_occluded_volume_all_func(args);
break;
}
case CCLIntersectContext::RAY_REGULAR:
default:
if (kernel_embree_is_self_intersection(
kg, hit, cray, reinterpret_cast<intptr_t>(args->geometryUserPtr))) {
*args->valid = 0;
return;
}
/* We should never reach this point, because
* REGULAR intersection is handled in intersection filter. */
kernel_assert(false);
break;
}
}
@ -441,7 +544,7 @@ ccl_device void kernel_embree_filter_func_backface_cull(const RTCFilterFunctionN
return;
}
CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
CCLIntersectContext *ctx = ((CCLIntersectContext *)args->context);
const KernelGlobalsCPU *kg = ctx->kg;
const Ray *cray = ctx->ray;
@ -467,6 +570,8 @@ ccl_device void kernel_embree_filter_occluded_func_backface_cull(
kernel_embree_filter_occluded_func(args);
}
#endif
/* Scene intersection. */
ccl_device_intersect bool kernel_embree_intersect(KernelGlobals kg,
@ -475,12 +580,29 @@ ccl_device_intersect bool kernel_embree_intersect(KernelGlobals kg,
ccl_private Intersection *isect)
{
isect->t = ray->tmax;
#if EMBREE_MAJOR_VERSION >= 4
CCLFirstHitContext ctx;
rtcInitRayQueryContext(&ctx);
ctx.kg = kg;
#else
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_REGULAR);
IntersectContext rtc_ctx(&ctx);
rtcInitIntersectContext(&ctx);
#endif
RTCRayHit ray_hit;
ctx.ray = ray;
kernel_embree_setup_rayhit(*ray, ray_hit, visibility);
rtcIntersect1(kernel_data.device_bvh, &rtc_ctx.context, &ray_hit);
#if EMBREE_MAJOR_VERSION >= 4
RTCIntersectArguments args;
rtcInitIntersectArguments(&args);
args.filter = (RTCFilterFunctionN)kernel_embree_filter_intersection_func;
args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
args.context = &ctx;
rtcIntersect1(kernel_data.device_bvh, &ray_hit, &args);
#else
rtcIntersect1(kernel_data.device_bvh, &ctx, &ray_hit);
#endif
if (ray_hit.hit.geomID == RTC_INVALID_GEOMETRY_ID ||
ray_hit.hit.primID == RTC_INVALID_GEOMETRY_ID) {
return false;
@ -500,8 +622,16 @@ ccl_device_intersect bool kernel_embree_intersect_local(KernelGlobals kg,
{
const bool has_bvh = !(kernel_data_fetch(object_flag, local_object) &
SD_OBJECT_TRANSFORM_APPLIED);
# if EMBREE_MAJOR_VERSION >= 4
CCLLocalContext ctx;
rtcInitRayQueryContext(&ctx);
ctx.kg = kg;
# else
CCLIntersectContext ctx(kg,
has_bvh ? CCLIntersectContext::RAY_SSS : CCLIntersectContext::RAY_LOCAL);
rtcInitIntersectContext(&ctx);
# endif
ctx.is_sss = has_bvh;
ctx.lcg_state = lcg_state;
ctx.max_hits = max_hits;
ctx.ray = ray;
@ -510,36 +640,49 @@ ccl_device_intersect bool kernel_embree_intersect_local(KernelGlobals kg,
local_isect->num_hits = 0;
}
ctx.local_object_id = local_object;
IntersectContext rtc_ctx(&ctx);
RTCRay rtc_ray;
kernel_embree_setup_ray(*ray, rtc_ray, PATH_RAY_ALL_VISIBILITY);
# if EMBREE_MAJOR_VERSION >= 4
RTCOccludedArguments args;
rtcInitOccludedArguments(&args);
args.filter = (RTCFilterFunctionN)(kernel_embree_filter_occluded_local_func);
args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
args.context = &ctx;
# endif
/* If this object has its own BVH, use it. */
if (has_bvh) {
RTCGeometry geom = rtcGetGeometry(kernel_data.device_bvh, local_object * 2);
if (geom) {
float3 P = ray->P;
float3 dir = ray->D;
float3 idir = ray->D;
bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir);
float3 P = ray->P;
float3 dir = ray->D;
float3 idir = ray->D;
bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir);
rtc_ray.org_x = P.x;
rtc_ray.org_y = P.y;
rtc_ray.org_z = P.z;
rtc_ray.dir_x = dir.x;
rtc_ray.dir_y = dir.y;
rtc_ray.dir_z = dir.z;
rtc_ray.tnear = ray->tmin;
rtc_ray.tfar = ray->tmax;
RTCScene scene = (RTCScene)rtcGetGeometryUserData(geom);
kernel_assert(scene);
if (scene) {
rtcOccluded1(scene, &rtc_ctx.context, &rtc_ray);
}
rtc_ray.org_x = P.x;
rtc_ray.org_y = P.y;
rtc_ray.org_z = P.z;
rtc_ray.dir_x = dir.x;
rtc_ray.dir_y = dir.y;
rtc_ray.dir_z = dir.z;
rtc_ray.tnear = ray->tmin;
rtc_ray.tfar = ray->tmax;
RTCScene scene = (RTCScene)rtcGetGeometryUserDataFromScene(kernel_data.device_bvh,
local_object * 2);
kernel_assert(scene);
if (scene) {
# if EMBREE_MAJOR_VERSION >= 4
rtcOccluded1(scene, &rtc_ray, &args);
# else
rtcOccluded1(scene, &ctx, &rtc_ray);
# endif
}
}
else {
rtcOccluded1(kernel_data.device_bvh, &rtc_ctx.context, &rtc_ray);
# if EMBREE_MAJOR_VERSION >= 4
rtcOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
# else
rtcOccluded1(kernel_data.device_bvh, &ctx, &rtc_ray);
# endif
}
/* rtcOccluded1 sets tfar to -inf if a hit was found. */
@ -556,14 +699,32 @@ ccl_device_intersect bool kernel_embree_intersect_shadow_all(KernelGlobals kg,
ccl_private uint *num_recorded_hits,
ccl_private float *throughput)
{
# if EMBREE_MAJOR_VERSION >= 4
CCLShadowContext ctx;
rtcInitRayQueryContext(&ctx);
ctx.kg = kg;
# else
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_SHADOW_ALL);
rtcInitIntersectContext(&ctx);
# endif
ctx.num_hits = ctx.num_recorded_hits = numhit_t(0);
ctx.throughput = 1.0f;
ctx.opaque_hit = false;
ctx.isect_s = state;
ctx.max_hits = numhit_t(max_hits);
ctx.ray = ray;
IntersectContext rtc_ctx(&ctx);
RTCRay rtc_ray;
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
rtcOccluded1(kernel_data.device_bvh, &rtc_ctx.context, &rtc_ray);
# if EMBREE_MAJOR_VERSION >= 4
RTCOccludedArguments args;
rtcInitOccludedArguments(&args);
args.filter = (RTCFilterFunctionN)kernel_embree_filter_occluded_shadow_all_func;
args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
args.context = &ctx;
rtcOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
# else
rtcOccluded1(kernel_data.device_bvh, &ctx, &rtc_ray);
# endif
*num_recorded_hits = ctx.num_recorded_hits;
*throughput = ctx.throughput;
@ -578,15 +739,30 @@ ccl_device_intersect uint kernel_embree_intersect_volume(KernelGlobals kg,
const uint max_hits,
const uint visibility)
{
# if EMBREE_MAJOR_VERSION >= 4
CCLVolumeContext ctx;
rtcInitRayQueryContext(&ctx);
ctx.kg = kg;
# else
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_VOLUME_ALL);
rtcInitIntersectContext(&ctx);
# endif
ctx.vol_isect = isect;
ctx.max_hits = numhit_t(max_hits);
ctx.num_hits = numhit_t(0);
ctx.ray = ray;
IntersectContext rtc_ctx(&ctx);
RTCRay rtc_ray;
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
rtcOccluded1(kernel_data.device_bvh, &rtc_ctx.context, &rtc_ray);
# if EMBREE_MAJOR_VERSION >= 4
RTCOccludedArguments args;
rtcInitOccludedArguments(&args);
args.filter = (RTCFilterFunctionN)kernel_embree_filter_occluded_volume_all_func;
args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
args.context = &ctx;
rtcOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
# else
rtcOccluded1(kernel_data.device_bvh, &ctx, &rtc_ray);
# endif
return ctx.num_hits;
}
#endif

View File

@ -117,7 +117,7 @@ ccl_device_noinline bool light_sample(KernelGlobals kg,
if (kernel_data.integrator.use_light_tree) {
ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
emitter_index);
prim = kemitter->prim;
prim = kemitter->prim_id;
mesh_light = kemitter->mesh_light;
}
else

View File

@ -184,7 +184,7 @@ ccl_device bool compute_emitter_centroid_and_dir(KernelGlobals kg,
ccl_private float3 &centroid,
ccl_private packed_float3 &dir)
{
const int prim_id = kemitter->prim;
const int prim_id = kemitter->prim_id;
if (prim_id < 0) {
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ~prim_id);
centroid = klight->co;
@ -264,7 +264,7 @@ ccl_device void light_tree_emitter_importance(KernelGlobals kg,
return;
}
const int prim_id = kemitter->prim;
const int prim_id = kemitter->prim_id;
if (in_volume_segment) {
const float3 D = N_or_D;
@ -344,12 +344,12 @@ ccl_device void light_tree_node_importance(KernelGlobals kg,
{
max_importance = 0.0f;
min_importance = 0.0f;
if (knode->num_prims == 1) {
if (knode->num_emitters == 1) {
/* At a leaf node with only one emitter. */
light_tree_emitter_importance<in_volume_segment>(
kg, P, N_or_D, t, has_transmission, -knode->child_index, max_importance, min_importance);
}
else if (knode->num_prims != 0) {
else if (knode->num_emitters != 0) {
const BoundingCone bcone = knode->bcone;
const BoundingBox bbox = knode->bbox;
@ -452,13 +452,13 @@ ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg,
int selected_index = -1;
/* Mark emitters with zero importance. Used for resevoir when total minimum importance = 0. */
kernel_assert(knode->num_prims <= sizeof(uint) * 8);
kernel_assert(knode->num_emitters <= sizeof(uint) * 8);
uint has_importance = 0;
const bool sample_max = (rand > 0.5f); /* Sampling using the maximum importance. */
rand = rand * 2.0f - float(sample_max);
for (int i = 0; i < knode->num_prims; i++) {
for (int i = 0; i < knode->num_emitters; i++) {
int current_index = -knode->child_index + i;
/* maximum importance = importance[0], minimum importance = importance[1] */
float importance[2];
@ -491,7 +491,7 @@ ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg,
}
else {
selected_index = -1;
for (int i = 0; i < knode->num_prims; i++) {
for (int i = 0; i < knode->num_emitters; i++) {
int current_index = -knode->child_index + i;
sample_resevoir(current_index,
float(has_importance & 1),
@ -615,12 +615,12 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
/* We need to be able to find the probability of selecting a given light for MIS. */
ccl_device float light_tree_pdf(
KernelGlobals kg, const float3 P, const float3 N, const int path_flag, const int prim)
KernelGlobals kg, const float3 P, const float3 N, const int path_flag, const int emitter)
{
const bool has_transmission = (path_flag & PATH_RAY_MIS_HAD_TRANSMISSION);
/* Target emitter info. */
const int target_emitter = (prim >= 0) ? kernel_data_fetch(triangle_to_tree, prim) :
kernel_data_fetch(light_to_tree, ~prim);
const int target_emitter = (emitter >= 0) ? kernel_data_fetch(triangle_to_tree, emitter) :
kernel_data_fetch(light_to_tree, ~emitter);
ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
target_emitter);
const int target_leaf = kemitter->parent_index;
@ -667,7 +667,7 @@ ccl_device float light_tree_pdf(
float total_max_importance = 0.0f;
float total_min_importance = 0.0f;
int num_has_importance = 0;
for (int i = 0; i < kleaf->num_prims; i++) {
for (int i = 0; i < kleaf->num_emitters; i++) {
const int emitter = -kleaf->child_index + i;
float max_importance, min_importance;
light_tree_emitter_importance<false>(

View File

@ -306,7 +306,7 @@ ccl_device_forceinline bool triangle_light_tree_parameters(
const int object = kemitter->mesh_light.object_id;
float3 vertices[3];
triangle_world_space_vertices(kg, object, kemitter->prim, -1.0f, vertices);
triangle_world_space_vertices(kg, object, kemitter->prim_id, -1.0f, vertices);
bool shape_above_surface = false;
for (int i = 0; i < 3; i++) {

View File

@ -18,7 +18,7 @@ ccl_device_noinline int svm_node_tex_coord(KernelGlobals kg,
uint4 node,
int offset)
{
float3 data;
float3 data = zero_float3();
uint type = node.y;
uint out_offset = node.z;
@ -100,7 +100,7 @@ ccl_device_noinline int svm_node_tex_coord_bump_dx(KernelGlobals kg,
int offset)
{
#ifdef __RAY_DIFFERENTIALS__
float3 data;
float3 data = zero_float3();
uint type = node.y;
uint out_offset = node.z;
@ -185,7 +185,7 @@ ccl_device_noinline int svm_node_tex_coord_bump_dy(KernelGlobals kg,
int offset)
{
#ifdef __RAY_DIFFERENTIALS__
float3 data;
float3 data = zero_float3();
uint type = node.y;
uint out_offset = node.z;

View File

@ -4,8 +4,13 @@
#pragma once
#if !defined(__KERNEL_GPU__) && defined(WITH_EMBREE)
# include <embree3/rtcore.h>
# include <embree3/rtcore_scene.h>
# if EMBREE_MAJOR_VERSION >= 4
# include <embree4/rtcore.h>
# include <embree4/rtcore_scene.h>
# else
# include <embree3/rtcore.h>
# include <embree3/rtcore_scene.h>
# endif
# define __EMBREE__
#endif
@ -1379,7 +1384,7 @@ typedef struct KernelLightTreeNode {
* and the negative value indexes into the first child of the light array.
* Otherwise, it's an index to the node's second child. */
int child_index;
int num_prims; /* leaf nodes need to know the number of primitives stored. */
int num_emitters; /* leaf nodes need to know the number of emitters stored. */
/* Bit trail. */
uint bit_trail;
@ -1397,8 +1402,8 @@ typedef struct KernelLightTreeEmitter {
/* Energy. */
float energy;
/* prim_id denotes the location in the lights or triangles array. */
int prim;
/* The location in the lights or triangles array. */
int prim_id;
MeshLight mesh_light;
EmissionSampling emission_sampling;

View File

@ -247,13 +247,16 @@ size_t CachedData::memory_used() const
static M44d convert_yup_zup(const M44d &mtx, float scale_mult)
{
V3d scale, shear, rotation, translation;
extractSHRT(mtx,
scale,
shear,
rotation,
translation,
true,
IMATH_INTERNAL_NAMESPACE::Euler<double>::XZY);
if (!extractSHRT(mtx,
scale,
shear,
rotation,
translation,
true,
IMATH_INTERNAL_NAMESPACE::Euler<double>::XZY)) {
return mtx;
}
M44d rot_mat, scale_mat, trans_mat;
rot_mat.setEulerAngles(V3d(rotation.x, -rotation.z, rotation.y));

View File

@ -531,7 +531,7 @@ PrimitiveType Hair::primitive_type() const
/* Fill in coordinates for curve transparency shader evaluation on device. */
static int fill_shader_input(const Hair *hair,
const int object_index,
const size_t object_index,
device_vector<KernelShaderEvalInput> &d_input)
{
int d_input_size = 0;

View File

@ -86,7 +86,7 @@ ImageHandle::ImageHandle(const ImageHandle &other)
: tile_slots(other.tile_slots), manager(other.manager)
{
/* Increase image user count. */
foreach (const int slot, tile_slots) {
foreach (const size_t slot, tile_slots) {
manager->add_image_user(slot);
}
}
@ -97,7 +97,7 @@ ImageHandle &ImageHandle::operator=(const ImageHandle &other)
manager = other.manager;
tile_slots = other.tile_slots;
foreach (const int slot, tile_slots) {
foreach (const size_t slot, tile_slots) {
manager->add_image_user(slot);
}
@ -111,7 +111,7 @@ ImageHandle::~ImageHandle()
void ImageHandle::clear()
{
foreach (const int slot, tile_slots) {
foreach (const size_t slot, tile_slots) {
manager->remove_image_user(slot);
}
@ -165,7 +165,7 @@ vector<int4> ImageHandle::get_svm_slots() const
for (size_t i = 0; i < num_nodes; i++) {
int4 node;
int slot = tile_slots[2 * i];
size_t slot = tile_slots[2 * i];
node.x = manager->images[slot]->loader->get_tile_number();
node.y = slot;
@ -387,7 +387,7 @@ void ImageManager::load_image_metadata(Image *img)
ImageHandle ImageManager::add_image(const string &filename, const ImageParams &params)
{
const int slot = add_image_slot(new OIIOImageLoader(filename), params, false);
const size_t slot = add_image_slot(new OIIOImageLoader(filename), params, false);
ImageHandle handle;
handle.tile_slots.push_back(slot);
@ -408,13 +408,13 @@ ImageHandle ImageManager::add_image(const string &filename,
/* Since we don't have information about the exact tile format used in this code location,
* just attempt all replacement patterns that Blender supports. */
if (tile != 0) {
string_replace(tile_filename, "<UDIM>", string_printf("%04d", tile));
string_replace(tile_filename, "<UDIM>", string_printf("%04d", (int)tile));
int u = ((tile - 1001) % 10);
int v = ((tile - 1001) / 10);
string_replace(tile_filename, "<UVTILE>", string_printf("u%d_v%d", u + 1, v + 1));
}
const int slot = add_image_slot(new OIIOImageLoader(tile_filename), params, false);
const size_t slot = add_image_slot(new OIIOImageLoader(tile_filename), params, false);
handle.tile_slots.push_back(slot);
}
@ -425,7 +425,7 @@ ImageHandle ImageManager::add_image(ImageLoader *loader,
const ImageParams &params,
const bool builtin)
{
const int slot = add_image_slot(loader, params, builtin);
const size_t slot = add_image_slot(loader, params, builtin);
ImageHandle handle;
handle.tile_slots.push_back(slot);
@ -438,7 +438,7 @@ ImageHandle ImageManager::add_image(const vector<ImageLoader *> &loaders,
{
ImageHandle handle;
for (ImageLoader *loader : loaders) {
const int slot = add_image_slot(loader, params, true);
const size_t slot = add_image_slot(loader, params, true);
handle.tile_slots.push_back(slot);
}
@ -446,9 +446,9 @@ ImageHandle ImageManager::add_image(const vector<ImageLoader *> &loaders,
return handle;
}
int ImageManager::add_image_slot(ImageLoader *loader,
const ImageParams &params,
const bool builtin)
size_t ImageManager::add_image_slot(ImageLoader *loader,
const ImageParams &params,
const bool builtin)
{
Image *img;
size_t slot;
@ -492,7 +492,7 @@ int ImageManager::add_image_slot(ImageLoader *loader,
return slot;
}
void ImageManager::add_image_user(int slot)
void ImageManager::add_image_user(size_t slot)
{
thread_scoped_lock device_lock(images_mutex);
Image *image = images[slot];
@ -501,7 +501,7 @@ void ImageManager::add_image_user(int slot)
image->users++;
}
void ImageManager::remove_image_user(int slot)
void ImageManager::remove_image_user(size_t slot)
{
thread_scoped_lock device_lock(images_mutex);
Image *image = images[slot];
@ -682,7 +682,7 @@ bool ImageManager::file_load_image(Image *img, int texture_limit)
return true;
}
void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Progress *progress)
void ImageManager::device_load_image(Device *device, Scene *scene, size_t slot, Progress *progress)
{
if (progress->get_cancel()) {
return;
@ -698,7 +698,7 @@ void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Pro
ImageDataType type = img->metadata.type;
/* Name for debugging. */
img->mem_name = string_printf("tex_image_%s_%03d", name_from_type(type), slot);
img->mem_name = string_printf("tex_image_%s_%03d", name_from_type(type), (int)slot);
/* Free previous texture in slot. */
if (img->mem) {
@ -819,7 +819,7 @@ void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Pro
img->need_load = false;
}
void ImageManager::device_free_image(Device *, int slot)
void ImageManager::device_free_image(Device *, size_t slot)
{
Image *img = images[slot];
if (img == NULL) {
@ -874,7 +874,10 @@ void ImageManager::device_update(Device *device, Scene *scene, Progress &progres
need_update_ = false;
}
void ImageManager::device_update_slot(Device *device, Scene *scene, int slot, Progress *progress)
void ImageManager::device_update_slot(Device *device,
Scene *scene,
size_t slot,
Progress *progress)
{
Image *img = images[slot];
assert(img != NULL);

View File

@ -156,7 +156,7 @@ class ImageHandle {
ImageManager *get_manager() const;
protected:
vector<int> tile_slots;
vector<size_t> tile_slots;
ImageManager *manager;
friend class ImageManager;
@ -179,7 +179,7 @@ class ImageManager {
ImageHandle add_image(const vector<ImageLoader *> &loaders, const ImageParams &params);
void device_update(Device *device, Scene *scene, Progress &progress);
void device_update_slot(Device *device, Scene *scene, int slot, Progress *progress);
void device_update_slot(Device *device, Scene *scene, size_t slot, Progress *progress);
void device_free(Device *device);
void device_load_builtin(Device *device, Scene *scene, Progress &progress);
@ -223,17 +223,17 @@ class ImageManager {
vector<Image *> images;
void *osl_texture_system;
int add_image_slot(ImageLoader *loader, const ImageParams &params, const bool builtin);
void add_image_user(int slot);
void remove_image_user(int slot);
size_t add_image_slot(ImageLoader *loader, const ImageParams &params, const bool builtin);
void add_image_user(size_t slot);
void remove_image_user(size_t slot);
void load_image_metadata(Image *img);
template<TypeDesc::BASETYPE FileFormat, typename StorageType>
bool file_load_image(Image *img, int texture_limit);
void device_load_image(Device *device, Scene *scene, int slot, Progress *progress);
void device_free_image(Device *device, int slot);
void device_load_image(Device *device, Scene *scene, size_t slot, Progress *progress);
void device_free_image(Device *device, size_t slot);
friend class ImageHandle;
};

View File

@ -264,9 +264,9 @@ void LightManager::device_update_distribution(Device *,
/* Count emissive triangles. */
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
size_t mesh_num_triangles = mesh->num_triangles();
int mesh_num_triangles = static_cast<int>(mesh->num_triangles());
for (size_t i = 0; i < mesh_num_triangles; i++) {
for (int i = 0; i < mesh_num_triangles; i++) {
int shader_index = mesh->get_shader()[i];
Shader *shader = (shader_index < mesh->get_used_shaders().size()) ?
static_cast<Shader *>(mesh->get_used_shaders()[shader_index]) :
@ -445,91 +445,23 @@ void LightManager::device_update_tree(Device *,
/* Update light tree. */
progress.set_status("Updating Lights", "Computing tree");
/* Add both lights and emissive triangles to this vector for light tree construction. */
vector<LightTreePrimitive> light_prims;
light_prims.reserve(kintegrator->num_distribution);
vector<LightTreePrimitive> distant_lights;
distant_lights.reserve(kintegrator->num_distant_lights);
vector<uint> object_lookup_offsets(scene->objects.size());
/* When we keep track of the light index, only contributing lights will be added to the device.
* Therefore, we want to keep track of the light's index on the device.
* However, we also need the light's index in the scene when we're constructing the tree. */
int device_light_index = 0;
int scene_light_index = 0;
foreach (Light *light, scene->lights) {
if (light->is_enabled) {
if (light->light_type == LIGHT_BACKGROUND || light->light_type == LIGHT_DISTANT) {
distant_lights.emplace_back(scene, ~device_light_index, scene_light_index);
}
else {
light_prims.emplace_back(scene, ~device_light_index, scene_light_index);
}
device_light_index++;
}
scene_light_index++;
}
/* Similarly, we also want to keep track of the index of triangles that are emissive. */
size_t total_triangles = 0;
int object_id = 0;
foreach (Object *object, scene->objects) {
if (progress.get_cancel())
return;
if (!object->usable_as_light()) {
object_id++;
continue;
}
object_lookup_offsets[object_id] = total_triangles;
/* Count emissive triangles. */
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
size_t mesh_num_triangles = mesh->num_triangles();
for (size_t i = 0; i < mesh_num_triangles; i++) {
int shader_index = mesh->get_shader()[i];
Shader *shader = (shader_index < mesh->get_used_shaders().size()) ?
static_cast<Shader *>(mesh->get_used_shaders()[shader_index]) :
scene->default_surface;
if (shader->emission_sampling != EMISSION_SAMPLING_NONE) {
light_prims.emplace_back(scene, i, object_id);
}
}
total_triangles += mesh_num_triangles;
object_id++;
}
/* Append distant lights to the end of `light_prims` */
std::move(distant_lights.begin(), distant_lights.end(), std::back_inserter(light_prims));
/* Update integrator state. */
kintegrator->use_direct_light = !light_prims.empty();
/* TODO: For now, we'll start with a smaller number of max lights in a node.
* More benchmarking is needed to determine what number works best. */
LightTree light_tree(light_prims, kintegrator->num_distant_lights, 8);
LightTree light_tree(scene, dscene, progress, 8);
LightTreeNode *root = light_tree.build(scene, dscene);
/* We want to create separate arrays corresponding to triangles and lights,
* which will be used to index back into the light tree for PDF calculations. */
const size_t num_lights = kintegrator->num_lights;
uint *light_array = dscene->light_to_tree.alloc(num_lights);
uint *object_offsets = dscene->object_lookup_offset.alloc(object_lookup_offsets.size());
uint *triangle_array = dscene->triangle_to_tree.alloc(total_triangles);
for (int i = 0; i < object_lookup_offsets.size(); i++) {
object_offsets[i] = object_lookup_offsets[i];
}
uint *light_array = dscene->light_to_tree.alloc(kintegrator->num_lights);
uint *triangle_array = dscene->triangle_to_tree.alloc(light_tree.num_triangles);
/* First initialize the light tree's nodes. */
KernelLightTreeNode *light_tree_nodes = dscene->light_tree_nodes.alloc(light_tree.size());
KernelLightTreeEmitter *light_tree_emitters = dscene->light_tree_emitters.alloc(
light_prims.size());
const size_t num_emitters = light_tree.num_emitters();
KernelLightTreeNode *light_tree_nodes = dscene->light_tree_nodes.alloc(light_tree.num_nodes);
KernelLightTreeEmitter *light_tree_emitters = dscene->light_tree_emitters.alloc(num_emitters);
/* Update integrator state. */
kintegrator->use_direct_light = num_emitters > 0;
/* Copy the light tree nodes to an array in the device. */
/* The nodes are arranged in a depth-first order, meaning the left child of each inner node
@ -544,40 +476,40 @@ void LightManager::device_update_tree(Device *,
int left_index_stack[32]; /* `sizeof(bit_trail) * 8 == 32`. */
LightTreeNode *right_node_stack[32];
int stack_id = 0;
const LightTreeNode *node = light_tree.get_root();
for (int index = 0; index < light_tree.size(); index++) {
light_tree_nodes[index].energy = node->measure.energy;
const LightTreeNode *node = root;
for (int node_index = 0; node_index < light_tree.num_nodes; node_index++) {
light_tree_nodes[node_index].energy = node->measure.energy;
light_tree_nodes[index].bbox.min = node->measure.bbox.min;
light_tree_nodes[index].bbox.max = node->measure.bbox.max;
light_tree_nodes[node_index].bbox.min = node->measure.bbox.min;
light_tree_nodes[node_index].bbox.max = node->measure.bbox.max;
light_tree_nodes[index].bcone.axis = node->measure.bcone.axis;
light_tree_nodes[index].bcone.theta_o = node->measure.bcone.theta_o;
light_tree_nodes[index].bcone.theta_e = node->measure.bcone.theta_e;
light_tree_nodes[node_index].bcone.axis = node->measure.bcone.axis;
light_tree_nodes[node_index].bcone.theta_o = node->measure.bcone.theta_o;
light_tree_nodes[node_index].bcone.theta_e = node->measure.bcone.theta_e;
light_tree_nodes[index].bit_trail = node->bit_trail;
light_tree_nodes[index].num_prims = node->num_prims;
light_tree_nodes[node_index].bit_trail = node->bit_trail;
light_tree_nodes[node_index].num_emitters = node->num_emitters;
/* Here we need to make a distinction between interior and leaf nodes. */
if (node->is_leaf()) {
light_tree_nodes[index].child_index = -node->first_prim_index;
light_tree_nodes[node_index].child_index = -node->first_emitter_index;
for (int i = 0; i < node->num_prims; i++) {
int emitter_index = i + node->first_prim_index;
LightTreePrimitive &prim = light_prims[emitter_index];
for (int i = 0; i < node->num_emitters; i++) {
int emitter_index = i + node->first_emitter_index;
const LightTreeEmitter &emitter = light_tree.get_emitter(emitter_index);
light_tree_emitters[emitter_index].energy = prim.measure.energy;
light_tree_emitters[emitter_index].theta_o = prim.measure.bcone.theta_o;
light_tree_emitters[emitter_index].theta_e = prim.measure.bcone.theta_e;
light_tree_emitters[emitter_index].energy = emitter.measure.energy;
light_tree_emitters[emitter_index].theta_o = emitter.measure.bcone.theta_o;
light_tree_emitters[emitter_index].theta_e = emitter.measure.bcone.theta_e;
if (prim.is_triangle()) {
light_tree_emitters[emitter_index].mesh_light.object_id = prim.object_id;
if (emitter.is_triangle()) {
light_tree_emitters[emitter_index].mesh_light.object_id = emitter.object_id;
int shader_flag = 0;
Object *object = scene->objects[prim.object_id];
Object *object = scene->objects[emitter.object_id];
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
Shader *shader = static_cast<Shader *>(
mesh->get_used_shaders()[mesh->get_shader()[prim.prim_id]]);
mesh->get_used_shaders()[mesh->get_shader()[emitter.prim_id]]);
if (!(object->get_visibility() & PATH_RAY_CAMERA)) {
shader_flag |= SHADER_EXCLUDE_CAMERA;
@ -598,19 +530,20 @@ void LightManager::device_update_tree(Device *,
shader_flag |= SHADER_EXCLUDE_SHADOW_CATCHER;
}
light_tree_emitters[emitter_index].prim = prim.prim_id + mesh->prim_offset;
light_tree_emitters[emitter_index].prim_id = emitter.prim_id + mesh->prim_offset;
light_tree_emitters[emitter_index].mesh_light.shader_flag = shader_flag;
light_tree_emitters[emitter_index].emission_sampling = shader->emission_sampling;
triangle_array[prim.prim_id + object_lookup_offsets[prim.object_id]] = emitter_index;
triangle_array[emitter.prim_id + dscene->object_lookup_offset[emitter.object_id]] =
emitter_index;
}
else {
light_tree_emitters[emitter_index].prim = prim.prim_id;
light_tree_emitters[emitter_index].prim_id = emitter.prim_id;
light_tree_emitters[emitter_index].mesh_light.shader_flag = 0;
light_tree_emitters[emitter_index].mesh_light.object_id = OBJECT_NONE;
light_tree_emitters[emitter_index].emission_sampling = EMISSION_SAMPLING_FRONT_BACK;
light_array[~prim.prim_id] = emitter_index;
light_array[~emitter.prim_id] = emitter_index;
}
light_tree_emitters[emitter_index].parent_index = index;
light_tree_emitters[emitter_index].parent_index = node_index;
}
/* Retrieve from the stacks. */
@ -618,12 +551,12 @@ void LightManager::device_update_tree(Device *,
break;
}
stack_id--;
light_tree_nodes[left_index_stack[stack_id]].child_index = index + 1;
light_tree_nodes[left_index_stack[stack_id]].child_index = node_index + 1;
node = right_node_stack[stack_id];
}
else {
/* Fill in the stacks. */
left_index_stack[stack_id] = index;
left_index_stack[stack_id] = node_index;
right_node_stack[stack_id] = node->children[LightTree::right].get();
node = node->children[LightTree::left].get();
stack_id++;
@ -634,7 +567,6 @@ void LightManager::device_update_tree(Device *,
dscene->light_tree_nodes.copy_to_device();
dscene->light_tree_emitters.copy_to_device();
dscene->light_to_tree.copy_to_device();
dscene->object_lookup_offset.copy_to_device();
dscene->triangle_to_tree.copy_to_device();
}

View File

@ -81,6 +81,7 @@ class Light : public Node {
bool has_contribution(Scene *scene);
friend class LightManager;
friend class LightTree;
};
class LightManager {

View File

@ -5,6 +5,8 @@
#include "scene/mesh.h"
#include "scene/object.h"
#include "util/progress.h"
CCL_NAMESPACE_BEGIN
float OrientationBounds::calculate_measure() const
@ -72,7 +74,7 @@ OrientationBounds merge(const OrientationBounds &cone_a, const OrientationBounds
return OrientationBounds({new_axis, theta_o, theta_e});
}
LightTreePrimitive::LightTreePrimitive(Scene *scene, int prim_id, int object_id)
LightTreeEmitter::LightTreeEmitter(Scene *scene, int prim_id, int object_id)
: prim_id(prim_id), object_id(object_id)
{
if (is_triangle()) {
@ -100,7 +102,7 @@ LightTreePrimitive::LightTreePrimitive(Scene *scene, int prim_id, int object_id)
float area = triangle_area(vertices[0], vertices[1], vertices[2]);
measure.energy = area * average(shader->emission_estimate);
/* NOTE: the original implementation used the bounding box centroid, but primitive centroid
/* NOTE: the original implementation used the bounding box centroid, but triangle centroid
* seems to work fine */
centroid = (vertices[0] + vertices[1] + vertices[2]) / 3.0f;
@ -208,80 +210,151 @@ LightTreePrimitive::LightTreePrimitive(Scene *scene, int prim_id, int object_id)
}
}
LightTree::LightTree(vector<LightTreePrimitive> &prims,
const int &num_distant_lights,
LightTree::LightTree(Scene *scene,
DeviceScene *dscene,
Progress &progress,
uint max_lights_in_leaf)
: progress_(progress), max_lights_in_leaf_(max_lights_in_leaf)
{
if (prims.empty()) {
return;
KernelIntegrator *kintegrator = &dscene->data.integrator;
/* Add both lights and emissive triangles to this vector for light tree construction. */
emitters_.reserve(kintegrator->num_distribution);
distant_lights_.reserve(kintegrator->num_distant_lights);
uint *object_offsets = dscene->object_lookup_offset.alloc(scene->objects.size());
/* When we keep track of the light index, only contributing lights will be added to the device.
* Therefore, we want to keep track of the light's index on the device.
* However, we also need the light's index in the scene when we're constructing the tree. */
int device_light_index = 0;
int scene_light_index = 0;
for (Light *light : scene->lights) {
if (light->is_enabled) {
if (light->light_type == LIGHT_BACKGROUND || light->light_type == LIGHT_DISTANT) {
distant_lights_.emplace_back(scene, ~device_light_index, scene_light_index);
}
else {
emitters_.emplace_back(scene, ~device_light_index, scene_light_index);
}
device_light_index++;
}
scene_light_index++;
}
max_lights_in_leaf_ = max_lights_in_leaf;
const int num_prims = prims.size();
const int num_local_lights = num_prims - num_distant_lights;
/* Similarly, we also want to keep track of the index of triangles that are emissive. */
int object_id = 0;
for (Object *object : scene->objects) {
if (progress_.get_cancel()) {
return;
}
root_ = create_node(LightTreePrimitivesMeasure::empty, 0);
if (!object->usable_as_light()) {
object_id++;
continue;
}
object_offsets[object_id] = num_triangles;
/* Count emissive triangles. */
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
size_t mesh_num_triangles = mesh->num_triangles();
for (size_t i = 0; i < mesh_num_triangles; i++) {
int shader_index = mesh->get_shader()[i];
Shader *shader = (shader_index < mesh->get_used_shaders().size()) ?
static_cast<Shader *>(mesh->get_used_shaders()[shader_index]) :
scene->default_surface;
if (shader->emission_sampling != EMISSION_SAMPLING_NONE) {
emitters_.emplace_back(scene, i, object_id);
}
}
num_triangles += mesh_num_triangles;
object_id++;
}
/* Copy array to device. */
dscene->object_lookup_offset.copy_to_device();
}
LightTreeNode *LightTree::build(Scene * /* scene */, DeviceScene * /* dscene */)
{
if (emitters_.empty() && distant_lights_.empty()) {
return nullptr;
}
/* At this stage `emitters_` only contains local lights, the distant lights will be merged
* into `emitters_` when Light Tree building is finished. */
const int num_local_lights = emitters_.size();
const int num_distant_lights = distant_lights_.size();
root_ = create_node(LightTreeMeasure::empty, 0);
/* All local lights are grouped to the left child as an inner node. */
recursive_build(left, root_.get(), 0, num_local_lights, &prims, 0, 1);
recursive_build(left, root_.get(), 0, num_local_lights, emitters_.data(), 0, 1);
task_pool.wait_work();
/* All distant lights are grouped to the right child as a leaf node. */
root_->children[right] = create_node(LightTreePrimitivesMeasure::empty, 1);
for (int i = num_local_lights; i < num_prims; i++) {
root_->children[right]->add(prims[i]);
root_->children[right] = create_node(LightTreeMeasure::empty, 1);
for (int i = 0; i < num_distant_lights; i++) {
root_->children[right]->add(distant_lights_[i]);
}
root_->children[right]->make_leaf(num_local_lights, num_distant_lights);
/* Append distant lights to the end of `light_prims` */
std::move(distant_lights_.begin(), distant_lights_.end(), std::back_inserter(emitters_));
return root_.get();
}
void LightTree::recursive_build(const Child child,
LightTreeNode *parent,
const int start,
const int end,
vector<LightTreePrimitive> *prims,
LightTreeEmitter *emitters,
const uint bit_trail,
const int depth)
{
BoundBox centroid_bounds = BoundBox::empty;
for (int i = start; i < end; i++) {
centroid_bounds.grow((*prims)[i].centroid);
if (progress_.get_cancel()) {
return;
}
parent->children[child] = create_node(LightTreePrimitivesMeasure::empty, bit_trail);
parent->children[child] = create_node(LightTreeMeasure::empty, bit_trail);
LightTreeNode *node = parent->children[child].get();
/* Find the best place to split the primitives into 2 nodes.
/* Find the best place to split the emitters into 2 nodes.
* If the best split cost is no better than making a leaf node, make a leaf instead. */
int split_dim = -1, middle;
if (should_split(*prims, start, middle, end, node->measure, centroid_bounds, split_dim)) {
if (should_split(emitters, start, middle, end, node->measure, split_dim)) {
if (split_dim != -1) {
/* Partition the primitives between start and end based on the centroids. */
std::nth_element(prims->begin() + start,
prims->begin() + middle,
prims->begin() + end,
[split_dim](const LightTreePrimitive &l, const LightTreePrimitive &r) {
/* Partition the emitters between start and end based on the centroids. */
std::nth_element(emitters + start,
emitters + middle,
emitters + end,
[split_dim](const LightTreeEmitter &l, const LightTreeEmitter &r) {
return l.centroid[split_dim] < r.centroid[split_dim];
});
}
/* Recursively build the left branch. */
if (middle - start > MIN_PRIMS_PER_THREAD) {
if (middle - start > MIN_EMITTERS_PER_THREAD) {
task_pool.push(
[=] { recursive_build(left, node, start, middle, prims, bit_trail, depth + 1); });
[=] { recursive_build(left, node, start, middle, emitters, bit_trail, depth + 1); });
}
else {
recursive_build(left, node, start, middle, prims, bit_trail, depth + 1);
recursive_build(left, node, start, middle, emitters, bit_trail, depth + 1);
}
/* Recursively build the right branch. */
if (end - middle > MIN_PRIMS_PER_THREAD) {
if (end - middle > MIN_EMITTERS_PER_THREAD) {
task_pool.push([=] {
recursive_build(right, node, middle, end, prims, bit_trail | (1u << depth), depth + 1);
recursive_build(right, node, middle, end, emitters, bit_trail | (1u << depth), depth + 1);
});
}
else {
recursive_build(right, node, middle, end, prims, bit_trail | (1u << depth), depth + 1);
recursive_build(right, node, middle, end, emitters, bit_trail | (1u << depth), depth + 1);
}
}
else {
@ -289,16 +362,29 @@ void LightTree::recursive_build(const Child child,
}
}
bool LightTree::should_split(const vector<LightTreePrimitive> &prims,
bool LightTree::should_split(LightTreeEmitter *emitters,
const int start,
int &middle,
const int end,
LightTreePrimitivesMeasure &measure,
const BoundBox &centroid_bbox,
LightTreeMeasure &measure,
int &split_dim)
{
const int num_emitters = end - start;
if (num_emitters < 2) {
if (num_emitters) {
/* Do not try to split if there is only one emitter. */
measure = (emitters + start)->measure;
}
return false;
}
middle = (start + end) / 2;
const int num_prims = end - start;
BoundBox centroid_bbox = BoundBox::empty;
for (int i = start; i < end; i++) {
centroid_bbox.grow((emitters + i)->centroid);
}
const float3 extent = centroid_bbox.size();
const float max_extent = max4(extent.x, extent.y, extent.z, 0.0f);
@ -313,18 +399,18 @@ bool LightTree::should_split(const vector<LightTreePrimitive> &prims,
const float inv_extent = 1 / (centroid_bbox.size()[dim]);
/* Fill in buckets with primitives. */
/* Fill in buckets with emitters. */
std::array<LightTreeBucket, LightTreeBucket::num_buckets> buckets;
for (int i = start; i < end; i++) {
const LightTreePrimitive &prim = prims[i];
const LightTreeEmitter *emitter = emitters + i;
/* Place primitive into the appropriate bucket, where the centroid box is split into equal
/* Place emitter into the appropriate bucket, where the centroid box is split into equal
* partitions. */
int bucket_idx = LightTreeBucket::num_buckets *
(prim.centroid[dim] - centroid_bbox.min[dim]) * inv_extent;
(emitter->centroid[dim] - centroid_bbox.min[dim]) * inv_extent;
bucket_idx = clamp(bucket_idx, 0, LightTreeBucket::num_buckets - 1);
buckets[bucket_idx].add(prim);
buckets[bucket_idx].add(*emitter);
}
/* Precompute the left bucket measure cumulatively. */
@ -338,12 +424,7 @@ bool LightTree::should_split(const vector<LightTreePrimitive> &prims,
/* Calculate node measure by summing up the bucket measure. */
measure = left_buckets.back().measure + buckets.back().measure;
/* Do not try to split if there are only one primitive. */
if (num_prims < 2) {
return false;
}
/* Degenerate case with co-located primitives. */
/* Degenerate case with co-located emitters. */
if (is_zero(centroid_bbox.size())) {
break;
}
@ -375,13 +456,12 @@ bool LightTree::should_split(const vector<LightTreePrimitive> &prims,
}
}
}
return min_cost < total_cost || num_prims > max_lights_in_leaf_;
return min_cost < total_cost || num_emitters > max_lights_in_leaf_;
}
__forceinline LightTreePrimitivesMeasure operator+(const LightTreePrimitivesMeasure &a,
const LightTreePrimitivesMeasure &b)
__forceinline LightTreeMeasure operator+(const LightTreeMeasure &a, const LightTreeMeasure &b)
{
LightTreePrimitivesMeasure c(a);
LightTreeMeasure c(a);
c.add(b);
return c;
}

View File

@ -58,25 +58,25 @@ OrientationBounds merge(const OrientationBounds &cone_a, const OrientationBounds
/* Light Tree uses the bounding box, the orientation bounding cone, and the energy of a cluster to
* compute the Surface Area Orientation Heuristic (SAOH). */
struct LightTreePrimitivesMeasure {
struct LightTreeMeasure {
BoundBox bbox = BoundBox::empty;
OrientationBounds bcone = OrientationBounds::empty;
float energy = 0.0f;
enum empty_t { empty = 0 };
__forceinline LightTreePrimitivesMeasure() = default;
__forceinline LightTreeMeasure() = default;
__forceinline LightTreePrimitivesMeasure(empty_t) {}
__forceinline LightTreeMeasure(empty_t) {}
__forceinline LightTreePrimitivesMeasure(const BoundBox &bbox,
const OrientationBounds &bcone,
const float &energy)
__forceinline LightTreeMeasure(const BoundBox &bbox,
const OrientationBounds &bcone,
const float &energy)
: bbox(bbox), bcone(bcone), energy(energy)
{
}
__forceinline LightTreePrimitivesMeasure(const LightTreePrimitivesMeasure &other)
__forceinline LightTreeMeasure(const LightTreeMeasure &other)
: bbox(other.bbox), bcone(other.bcone), energy(other.energy)
{
}
@ -86,7 +86,7 @@ struct LightTreePrimitivesMeasure {
return energy == 0;
}
__forceinline void add(const LightTreePrimitivesMeasure &measure)
__forceinline void add(const LightTreeMeasure &measure)
{
if (!measure.is_zero()) {
bbox.grow(measure.bbox);
@ -104,21 +104,20 @@ struct LightTreePrimitivesMeasure {
}
};
LightTreePrimitivesMeasure operator+(const LightTreePrimitivesMeasure &a,
const LightTreePrimitivesMeasure &b);
LightTreeMeasure operator+(const LightTreeMeasure &a, const LightTreeMeasure &b);
/* Light Tree Primitive
/* Light Tree Emitter
* Struct that indexes into the scene's triangle and light arrays. */
struct LightTreePrimitive {
struct LightTreeEmitter {
/* `prim_id >= 0` is an index into an object's local triangle index,
* otherwise `-prim_id-1`(`~prim`) is an index into device lights array. */
int prim_id;
int object_id;
float3 centroid;
LightTreePrimitivesMeasure measure;
LightTreeMeasure measure;
LightTreePrimitive(Scene *scene, int prim_id, int object_id);
LightTreeEmitter(Scene *scene, int prim_id, int object_id);
__forceinline bool is_triangle() const
{
@ -129,20 +128,20 @@ struct LightTreePrimitive {
/* Light Tree Bucket
* Struct used to determine splitting costs in the light BVH. */
struct LightTreeBucket {
LightTreePrimitivesMeasure measure;
LightTreeMeasure measure;
int count = 0;
static const int num_buckets = 12;
LightTreeBucket() = default;
LightTreeBucket(const LightTreePrimitivesMeasure &measure, const int &count)
LightTreeBucket(const LightTreeMeasure &measure, const int &count)
: measure(measure), count(count)
{
}
void add(const LightTreePrimitive &prim)
void add(const LightTreeEmitter &emitter)
{
measure.add(prim.measure);
measure.add(emitter.measure);
count++;
}
};
@ -151,34 +150,34 @@ LightTreeBucket operator+(const LightTreeBucket &a, const LightTreeBucket &b);
/* Light Tree Node */
struct LightTreeNode {
LightTreePrimitivesMeasure measure;
LightTreeMeasure measure;
uint bit_trail;
int num_prims = -1; /* The number of primitives a leaf node stores. A negative
number indicates it is an inner node. */
int first_prim_index; /* Leaf nodes contain an index to first primitive. */
int num_emitters = -1; /* The number of emitters a leaf node stores. A negative number indicates
it is an inner node. */
int first_emitter_index; /* Leaf nodes contain an index to first emitter. */
unique_ptr<LightTreeNode> children[2]; /* Inner node has two children. */
LightTreeNode() = default;
LightTreeNode(const LightTreePrimitivesMeasure &measure, const uint &bit_trial)
LightTreeNode(const LightTreeMeasure &measure, const uint &bit_trial)
: measure(measure), bit_trail(bit_trial)
{
}
__forceinline void add(const LightTreePrimitive &prim)
__forceinline void add(const LightTreeEmitter &emitter)
{
measure.add(prim.measure);
measure.add(emitter.measure);
}
void make_leaf(const int &first_prim_index, const int &num_prims)
void make_leaf(const int &first_emitter_index, const int &num_emitters)
{
this->first_prim_index = first_prim_index;
this->num_prims = num_prims;
this->first_emitter_index = first_emitter_index;
this->num_emitters = num_emitters;
}
__forceinline bool is_leaf() const
{
return num_prims >= 0;
return num_emitters >= 0;
}
};
@ -188,58 +187,65 @@ struct LightTreeNode {
* and considers additional orientation and energy information */
class LightTree {
unique_ptr<LightTreeNode> root_;
std::atomic<int> num_nodes_ = 0;
vector<LightTreeEmitter> emitters_;
vector<LightTreeEmitter> distant_lights_;
Progress &progress_;
uint max_lights_in_leaf_;
public:
std::atomic<int> num_nodes = 0;
size_t num_triangles = 0;
/* Left or right child of an inner node. */
enum Child {
left = 0,
right = 1,
};
LightTree(vector<LightTreePrimitive> &prims,
const int &num_distant_lights,
uint max_lights_in_leaf);
LightTree(Scene *scene, DeviceScene *dscene, Progress &progress, uint max_lights_in_leaf);
int size() const
{
return num_nodes_;
};
LightTreeNode *get_root() const
{
return root_.get();
};
/* Returns a pointer to the root node. */
LightTreeNode *build(Scene *scene, DeviceScene *dscene);
/* NOTE: Always use this function to create a new node so the number of nodes is in sync. */
unique_ptr<LightTreeNode> create_node(const LightTreePrimitivesMeasure &measure,
const uint &bit_trial)
unique_ptr<LightTreeNode> create_node(const LightTreeMeasure &measure, const uint &bit_trial)
{
num_nodes_++;
num_nodes++;
return make_unique<LightTreeNode>(measure, bit_trial);
}
size_t num_emitters()
{
return emitters_.size();
}
const LightTreeEmitter &get_emitter(int index) const
{
return emitters_.at(index);
}
private:
/* Thread. */
TaskPool task_pool;
/* Do not spawn a thread if less than this amount of primitives are to be processed. */
enum { MIN_PRIMS_PER_THREAD = 4096 };
/* Do not spawn a thread if less than this amount of emitters are to be processed. */
enum { MIN_EMITTERS_PER_THREAD = 4096 };
void recursive_build(Child child,
LightTreeNode *parent,
int start,
int end,
vector<LightTreePrimitive> *prims,
LightTreeEmitter *emitters,
uint bit_trail,
int depth);
bool should_split(const vector<LightTreePrimitive> &prims,
bool should_split(LightTreeEmitter *emitters,
const int start,
int &middle,
const int end,
LightTreePrimitivesMeasure &measure,
const BoundBox &centroid_bbox,
LightTreeMeasure &measure,
int &split_dim);
};

View File

@ -35,7 +35,7 @@ static float3 compute_face_normal(const Mesh::Triangle &t, float3 *verts)
/* Fill in coordinates for mesh displacement shader evaluation on device. */
static int fill_shader_input(const Scene *scene,
const Mesh *mesh,
const int object_index,
const size_t object_index,
device_vector<KernelShaderEvalInput> &d_input)
{
int d_input_size = 0;

View File

@ -40,7 +40,7 @@ ccl_device_inline float half_to_float(half h_in)
* unsigned shorts. */
class half {
public:
half() : v(0) {}
half() = default;
half(const unsigned short &i) : v(i) {}
operator unsigned short()
{

View File

@ -14,62 +14,62 @@ set(INC_SYS
)
set(SRC
intern/GHOST_Buttons.cpp
intern/GHOST_C-api.cpp
intern/GHOST_CallbackEventConsumer.cpp
intern/GHOST_Context.cpp
intern/GHOST_ContextNone.cpp
intern/GHOST_DisplayManager.cpp
intern/GHOST_EventManager.cpp
intern/GHOST_ISystem.cpp
intern/GHOST_ISystemPaths.cpp
intern/GHOST_ModifierKeys.cpp
intern/GHOST_Path-api.cpp
intern/GHOST_PathUtils.cpp
intern/GHOST_Rect.cpp
intern/GHOST_System.cpp
intern/GHOST_TimerManager.cpp
intern/GHOST_Window.cpp
intern/GHOST_WindowManager.cpp
intern/GHOST_Buttons.cc
intern/GHOST_C-api.cc
intern/GHOST_CallbackEventConsumer.cc
intern/GHOST_Context.cc
intern/GHOST_ContextNone.cc
intern/GHOST_DisplayManager.cc
intern/GHOST_EventManager.cc
intern/GHOST_ISystem.cc
intern/GHOST_ISystemPaths.cc
intern/GHOST_ModifierKeys.cc
intern/GHOST_Path-api.cc
intern/GHOST_PathUtils.cc
intern/GHOST_Rect.cc
intern/GHOST_System.cc
intern/GHOST_TimerManager.cc
intern/GHOST_Window.cc
intern/GHOST_WindowManager.cc
GHOST_C-api.h
GHOST_IContext.h
GHOST_IEvent.h
GHOST_IEventConsumer.h
GHOST_ISystem.h
GHOST_ISystemPaths.h
GHOST_ITimerTask.h
GHOST_IWindow.h
GHOST_Path-api.h
GHOST_Rect.h
GHOST_IContext.hh
GHOST_IEvent.hh
GHOST_IEventConsumer.hh
GHOST_ISystem.hh
GHOST_ISystemPaths.hh
GHOST_ITimerTask.hh
GHOST_IWindow.hh
GHOST_Path-api.hh
GHOST_Rect.hh
GHOST_Types.h
intern/GHOST_Buttons.h
intern/GHOST_CallbackEventConsumer.h
intern/GHOST_Context.h
intern/GHOST_ContextNone.h
intern/GHOST_Debug.h
intern/GHOST_DisplayManager.h
intern/GHOST_Event.h
intern/GHOST_EventButton.h
intern/GHOST_EventCursor.h
intern/GHOST_EventDragnDrop.h
intern/GHOST_EventKey.h
intern/GHOST_EventManager.h
intern/GHOST_EventString.h
intern/GHOST_EventTrackpad.h
intern/GHOST_EventWheel.h
intern/GHOST_ModifierKeys.h
intern/GHOST_PathUtils.h
intern/GHOST_System.h
intern/GHOST_SystemPaths.h
intern/GHOST_TimerManager.h
intern/GHOST_TimerTask.h
intern/GHOST_Util.h
intern/GHOST_Window.h
intern/GHOST_WindowManager.h
intern/GHOST_utildefines.h
intern/GHOST_utildefines_variadic.h
intern/GHOST_Buttons.hh
intern/GHOST_CallbackEventConsumer.hh
intern/GHOST_Context.hh
intern/GHOST_ContextNone.hh
intern/GHOST_Debug.hh
intern/GHOST_DisplayManager.hh
intern/GHOST_Event.hh
intern/GHOST_EventButton.hh
intern/GHOST_EventCursor.hh
intern/GHOST_EventDragnDrop.hh
intern/GHOST_EventKey.hh
intern/GHOST_EventManager.hh
intern/GHOST_EventString.hh
intern/GHOST_EventTrackpad.hh
intern/GHOST_EventWheel.hh
intern/GHOST_ModifierKeys.hh
intern/GHOST_PathUtils.hh
intern/GHOST_System.hh
intern/GHOST_SystemPaths.hh
intern/GHOST_TimerManager.hh
intern/GHOST_TimerTask.hh
intern/GHOST_Util.hh
intern/GHOST_Window.hh
intern/GHOST_WindowManager.hh
intern/GHOST_utildefines.hh
intern/GHOST_utildefines_variadic.hh
)
set(LIB
@ -78,9 +78,9 @@ set(LIB
if(WITH_VULKAN_BACKEND)
list(APPEND SRC
intern/GHOST_ContextVK.cpp
intern/GHOST_ContextVK.cc
intern/GHOST_ContextVK.h
intern/GHOST_ContextVK.hh
)
list(APPEND INC_SYS
@ -98,9 +98,9 @@ endif()
if(WITH_GHOST_DEBUG)
list(APPEND SRC
intern/GHOST_EventPrinter.cpp
intern/GHOST_EventPrinter.cc
intern/GHOST_EventPrinter.h
intern/GHOST_EventPrinter.hh
)
add_definitions(-DWITH_GHOST_DEBUG)
endif()
@ -109,10 +109,10 @@ if(WITH_INPUT_NDOF)
add_definitions(-DWITH_INPUT_NDOF)
list(APPEND SRC
intern/GHOST_NDOFManager.cpp
intern/GHOST_NDOFManager.cc
intern/GHOST_EventNDOF.h
intern/GHOST_NDOFManager.h
intern/GHOST_EventNDOF.hh
intern/GHOST_NDOFManager.hh
)
list(APPEND INC_SYS
@ -124,24 +124,24 @@ if(WITH_INPUT_NDOF)
endif()
list(APPEND SRC
intern/GHOST_DisplayManagerNULL.h
intern/GHOST_SystemHeadless.h
intern/GHOST_WindowNULL.h
intern/GHOST_DisplayManagerNULL.hh
intern/GHOST_SystemHeadless.hh
intern/GHOST_WindowNULL.hh
)
if(WITH_HEADLESS)
add_definitions(-DWITH_HEADLESS)
elseif(WITH_GHOST_SDL)
list(APPEND SRC
intern/GHOST_ContextSDL.cpp
intern/GHOST_DisplayManagerSDL.cpp
intern/GHOST_SystemSDL.cpp
intern/GHOST_WindowSDL.cpp
intern/GHOST_ContextSDL.cc
intern/GHOST_DisplayManagerSDL.cc
intern/GHOST_SystemSDL.cc
intern/GHOST_WindowSDL.cc
intern/GHOST_ContextSDL.h
intern/GHOST_DisplayManagerSDL.h
intern/GHOST_SystemSDL.h
intern/GHOST_WindowSDL.h
intern/GHOST_ContextSDL.hh
intern/GHOST_DisplayManagerSDL.hh
intern/GHOST_SystemSDL.hh
intern/GHOST_WindowSDL.hh
)
add_definitions(-DWITH_GHOST_SDL)
@ -167,23 +167,23 @@ elseif(APPLE AND NOT WITH_GHOST_X11)
intern/GHOST_SystemCocoa.mm
intern/GHOST_WindowCocoa.mm
intern/GHOST_DisplayManagerCocoa.h
intern/GHOST_SystemCocoa.h
intern/GHOST_WindowCocoa.h
intern/GHOST_WindowViewCocoa.h
intern/GHOST_DisplayManagerCocoa.hh
intern/GHOST_SystemCocoa.hh
intern/GHOST_WindowCocoa.hh
intern/GHOST_WindowViewCocoa.hh
)
list(APPEND SRC
intern/GHOST_ContextCGL.mm
intern/GHOST_ContextCGL.h
intern/GHOST_ContextCGL.hh
)
if(WITH_INPUT_NDOF)
list(APPEND SRC
intern/GHOST_NDOFManagerCocoa.mm
intern/GHOST_NDOFManagerCocoa.h
intern/GHOST_NDOFManagerCocoa.hh
)
endif()
@ -199,22 +199,22 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
)
list(APPEND SRC
intern/GHOST_DisplayManagerX11.cpp
intern/GHOST_SystemX11.cpp
intern/GHOST_TaskbarX11.cpp
intern/GHOST_WindowX11.cpp
intern/GHOST_DisplayManagerX11.cc
intern/GHOST_SystemX11.cc
intern/GHOST_TaskbarX11.cc
intern/GHOST_WindowX11.cc
intern/GHOST_DisplayManagerX11.h
intern/GHOST_IconX11.h
intern/GHOST_SystemX11.h
intern/GHOST_TaskbarX11.h
intern/GHOST_WindowX11.h
intern/GHOST_DisplayManagerX11.hh
intern/GHOST_IconX11.hh
intern/GHOST_SystemX11.hh
intern/GHOST_TaskbarX11.hh
intern/GHOST_WindowX11.hh
)
list(APPEND SRC
intern/GHOST_ContextGLX.cpp
intern/GHOST_ContextGLX.cc
intern/GHOST_ContextGLX.h
intern/GHOST_ContextGLX.hh
)
if(WITH_GHOST_XDND)
@ -229,9 +229,9 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
)
list(APPEND SRC
intern/GHOST_DropTargetX11.cpp
intern/GHOST_DropTargetX11.cc
intern/GHOST_DropTargetX11.h
intern/GHOST_DropTargetX11.hh
)
endif()
@ -336,13 +336,13 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
endif()
list(APPEND SRC
intern/GHOST_SystemWayland.cpp
intern/GHOST_WindowWayland.cpp
intern/GHOST_SystemWayland.cc
intern/GHOST_WindowWayland.cc
intern/GHOST_SystemWayland.h
intern/GHOST_WaylandCursorSettings.h
intern/GHOST_WaylandUtils.h
intern/GHOST_WindowWayland.h
intern/GHOST_SystemWayland.hh
intern/GHOST_WaylandCursorSettings.hh
intern/GHOST_WaylandUtils.hh
intern/GHOST_WindowWayland.hh
)
set(INC_DST ${CMAKE_CURRENT_BINARY_DIR}/libwayland)
@ -441,9 +441,9 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
if(WITH_INPUT_NDOF)
list(APPEND SRC
intern/GHOST_NDOFManagerUnix.cpp
intern/GHOST_NDOFManagerUnix.cc
intern/GHOST_NDOFManagerUnix.h
intern/GHOST_NDOFManagerUnix.hh
)
endif()
@ -463,67 +463,67 @@ elseif(WIN32)
)
list(APPEND SRC
intern/GHOST_ContextD3D.cpp
intern/GHOST_DisplayManagerWin32.cpp
intern/GHOST_DropTargetWin32.cpp
intern/GHOST_SystemWin32.cpp
intern/GHOST_TrackpadWin32.cpp
intern/GHOST_WindowWin32.cpp
intern/GHOST_Wintab.cpp
intern/GHOST_ContextD3D.cc
intern/GHOST_DisplayManagerWin32.cc
intern/GHOST_DropTargetWin32.cc
intern/GHOST_SystemWin32.cc
intern/GHOST_TrackpadWin32.cc
intern/GHOST_WindowWin32.cc
intern/GHOST_Wintab.cc
intern/GHOST_ContextD3D.h
intern/GHOST_DisplayManagerWin32.h
intern/GHOST_DropTargetWin32.h
intern/GHOST_SystemWin32.h
intern/GHOST_TaskbarWin32.h
intern/GHOST_TrackpadWin32.h
intern/GHOST_WindowWin32.h
intern/GHOST_Wintab.h
intern/GHOST_ContextD3D.hh
intern/GHOST_DisplayManagerWin32.hh
intern/GHOST_DropTargetWin32.hh
intern/GHOST_SystemWin32.hh
intern/GHOST_TaskbarWin32.hh
intern/GHOST_TrackpadWin32.hh
intern/GHOST_WindowWin32.hh
intern/GHOST_Wintab.hh
)
list(APPEND SRC
intern/GHOST_ContextWGL.cpp
intern/GHOST_ContextWGL.cc
intern/GHOST_ContextWGL.h
intern/GHOST_ContextWGL.hh
)
if(WITH_INPUT_IME)
add_definitions(-DWITH_INPUT_IME)
list(APPEND SRC
intern/GHOST_ImeWin32.cpp
intern/GHOST_ImeWin32.cc
intern/GHOST_ImeWin32.h
intern/GHOST_ImeWin32.hh
)
endif()
if(WITH_INPUT_NDOF)
list(APPEND SRC
intern/GHOST_NDOFManagerWin32.cpp
intern/GHOST_NDOFManagerWin32.cc
intern/GHOST_NDOFManagerWin32.h
intern/GHOST_NDOFManagerWin32.hh
)
endif()
endif()
if(UNIX AND NOT APPLE)
list(APPEND SRC
intern/GHOST_ContextEGL.cpp
intern/GHOST_ContextEGL.cc
intern/GHOST_ContextEGL.h
intern/GHOST_ContextEGL.hh
)
endif()
if(APPLE)
list(APPEND SRC
intern/GHOST_SystemPathsCocoa.h
intern/GHOST_SystemPathsCocoa.hh
intern/GHOST_SystemPathsCocoa.mm
)
elseif(UNIX)
list(APPEND SRC
intern/GHOST_SystemPathsUnix.cpp
intern/GHOST_SystemPathsUnix.h
intern/GHOST_SystemPathsUnix.cc
intern/GHOST_SystemPathsUnix.hh
)
if(NOT WITH_INSTALL_PORTABLE)
@ -532,8 +532,8 @@ elseif(UNIX)
elseif(WIN32)
list(APPEND SRC
intern/GHOST_SystemPathsWin32.cpp
intern/GHOST_SystemPathsWin32.h
intern/GHOST_SystemPathsWin32.cc
intern/GHOST_SystemPathsWin32.hh
)
list(APPEND INC
@ -544,25 +544,25 @@ endif()
if(WITH_XR_OPENXR)
list(APPEND SRC
intern/GHOST_Xr.cpp
intern/GHOST_XrAction.cpp
intern/GHOST_XrContext.cpp
intern/GHOST_XrControllerModel.cpp
intern/GHOST_XrEvent.cpp
intern/GHOST_XrGraphicsBinding.cpp
intern/GHOST_XrSession.cpp
intern/GHOST_XrSwapchain.cpp
intern/GHOST_Xr.cc
intern/GHOST_XrAction.cc
intern/GHOST_XrContext.cc
intern/GHOST_XrControllerModel.cc
intern/GHOST_XrEvent.cc
intern/GHOST_XrGraphicsBinding.cc
intern/GHOST_XrSession.cc
intern/GHOST_XrSwapchain.cc
GHOST_IXrContext.h
intern/GHOST_IXrGraphicsBinding.h
intern/GHOST_XrAction.h
intern/GHOST_XrContext.h
intern/GHOST_XrControllerModel.h
intern/GHOST_XrException.h
intern/GHOST_XrSession.h
intern/GHOST_XrSwapchain.h
intern/GHOST_Xr_intern.h
intern/GHOST_Xr_openxr_includes.h
GHOST_IXrContext.hh
intern/GHOST_IXrGraphicsBinding.hh
intern/GHOST_XrAction.hh
intern/GHOST_XrContext.hh
intern/GHOST_XrControllerModel.hh
intern/GHOST_XrException.hh
intern/GHOST_XrSession.hh
intern/GHOST_XrSwapchain.hh
intern/GHOST_Xr_intern.hh
intern/GHOST_Xr_openxr_includes.hh
# Header only library.
../../extern/tinygltf/tiny_gltf.h

View File

@ -8,7 +8,7 @@
#pragma once
#include "GHOST_IEvent.h"
#include "GHOST_IEvent.hh"
/**
* Interface class for objects interested in receiving events.

View File

@ -12,9 +12,9 @@
#include <stdlib.h>
#include "GHOST_IContext.h"
#include "GHOST_ITimerTask.h"
#include "GHOST_IWindow.h"
#include "GHOST_IContext.hh"
#include "GHOST_ITimerTask.hh"
#include "GHOST_IWindow.hh"
#include "GHOST_Types.h"
class GHOST_IEventConsumer;
@ -77,12 +77,12 @@ class GHOST_IEventConsumer;
*
* \subsection cplusplus_api The C++ API consists of the following files:
*
* - GHOST_IEvent.h
* - GHOST_IEventConsumer.h
* - GHOST_ISystem.h
* - GHOST_ITimerTask.h
* - GHOST_IWindow.h
* - GHOST_Rect.h
* - GHOST_IEvent.hh
* - GHOST_IEventConsumer.hh
* - GHOST_ISystem.hh
* - GHOST_ITimerTask.hh
* - GHOST_IWindow.hh
* - GHOST_Rect.hh
* - GHOST_Types.h
*
* For an example of using the C++-API, have a look at the GHOST_C-Test.cpp

View File

@ -8,7 +8,7 @@
#pragma once
#include "GHOST_Rect.h"
#include "GHOST_Rect.hh"
#include "GHOST_Types.h"
#include <stdlib.h>

View File

@ -5,7 +5,7 @@
* \ingroup GHOST
*/
#include "GHOST_Buttons.h"
#include "GHOST_Buttons.hh"
GHOST_Buttons::GHOST_Buttons()
{

View File

@ -11,16 +11,16 @@
#include <cstring>
#include "GHOST_C-api.h"
#include "GHOST_IEvent.h"
#include "GHOST_IEventConsumer.h"
#include "GHOST_ISystem.h"
#include "intern/GHOST_Debug.h"
#include "GHOST_IEvent.hh"
#include "GHOST_IEventConsumer.hh"
#include "GHOST_ISystem.hh"
#include "intern/GHOST_Debug.hh"
#ifdef WITH_XR_OPENXR
# include "GHOST_IXrContext.h"
# include "intern/GHOST_XrSession.h"
# include "GHOST_IXrContext.hh"
# include "intern/GHOST_XrSession.hh"
#endif
#include "intern/GHOST_CallbackEventConsumer.h"
#include "intern/GHOST_XrException.h"
#include "intern/GHOST_CallbackEventConsumer.hh"
#include "intern/GHOST_XrException.hh"
GHOST_SystemHandle GHOST_CreateSystem(void)
{

View File

@ -9,9 +9,9 @@
* Copyright (C) 2001 NaN Technologies B.V.
*/
#include "GHOST_CallbackEventConsumer.h"
#include "GHOST_CallbackEventConsumer.hh"
#include "GHOST_C-api.h"
#include "GHOST_Debug.h"
#include "GHOST_Debug.hh"
GHOST_CallbackEventConsumer::GHOST_CallbackEventConsumer(GHOST_EventCallbackProcPtr eventCallback,
GHOST_TUserDataPtr userData)

View File

@ -9,7 +9,7 @@
#pragma once
#include "GHOST_C-api.h"
#include "GHOST_IEventConsumer.h"
#include "GHOST_IEventConsumer.hh"
/**
* Event consumer that will forward events to a call-back routine.

View File

@ -7,7 +7,7 @@
* Definition of GHOST_Context class.
*/
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
#ifdef _WIN32
# include <epoxy/wgl.h>

View File

@ -8,7 +8,7 @@
#pragma once
#include "GHOST_IContext.h"
#include "GHOST_IContext.hh"
#include "GHOST_Types.h"
#include <epoxy/gl.h>

View File

@ -7,7 +7,7 @@
#pragma once
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
#include <Cocoa/Cocoa.h>
#include <Metal/Metal.h>

View File

@ -13,7 +13,7 @@
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
#include "GHOST_ContextCGL.h"
#include "GHOST_ContextCGL.hh"
#include <Cocoa/Cocoa.h>
#include <Metal/Metal.h>

View File

@ -12,8 +12,8 @@
#include <epoxy/wgl.h>
#include "GHOST_ContextD3D.h"
#include "GHOST_ContextWGL.h" /* For shared drawing */
#include "GHOST_ContextD3D.hh"
#include "GHOST_ContextWGL.hh" /* For shared drawing */
HMODULE GHOST_ContextD3D::s_d3d_lib = NULL;
PFN_D3D11_CREATE_DEVICE GHOST_ContextD3D::s_D3D11CreateDeviceFn = NULL;

View File

@ -12,7 +12,7 @@
#include <D3D11.h>
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
class GHOST_ContextD3D : public GHOST_Context {
/* XR code needs low level graphics data to send to OpenXR. */

View File

@ -7,7 +7,7 @@
* Definition of GHOST_ContextEGL class.
*/
#include "GHOST_ContextEGL.h"
#include "GHOST_ContextEGL.hh"
#include <set>
#include <sstream>

View File

@ -7,8 +7,8 @@
#pragma once
#include "GHOST_Context.h"
#include "GHOST_System.h"
#include "GHOST_Context.hh"
#include "GHOST_System.hh"
#include <epoxy/egl.h>
#include <epoxy/gl.h>

View File

@ -7,8 +7,8 @@
* Definition of GHOST_ContextGLX class.
*/
#include "GHOST_ContextGLX.h"
#include "GHOST_SystemX11.h"
#include "GHOST_ContextGLX.hh"
#include "GHOST_SystemX11.hh"
#include <vector>

View File

@ -7,7 +7,7 @@
#pragma once
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
#include <epoxy/glx.h>

View File

@ -7,7 +7,7 @@
* Definition of GHOST_ContextNone class.
*/
#include "GHOST_ContextNone.h"
#include "GHOST_ContextNone.hh"
GHOST_TSuccess GHOST_ContextNone::swapBuffers()
{

View File

@ -9,7 +9,7 @@
#pragma once
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
class GHOST_ContextNone : public GHOST_Context {
public:

View File

@ -7,7 +7,7 @@
* Definition of GHOST_ContextSDL class.
*/
#include "GHOST_ContextSDL.h"
#include "GHOST_ContextSDL.hh"
#include <vector>

View File

@ -7,7 +7,7 @@
#pragma once
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
extern "C" {
#include "SDL.h"

View File

@ -4,7 +4,7 @@
* \ingroup GHOST
*/
#include "GHOST_ContextVK.h"
#include "GHOST_ContextVK.hh"
#ifdef _WIN32
# include <vulkan/vulkan_win32.h>

View File

@ -6,16 +6,16 @@
#pragma once
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
#ifdef _WIN32
# include "GHOST_SystemWin32.h"
# include "GHOST_SystemWin32.hh"
#elif defined(__APPLE__)
# include "GHOST_SystemCocoa.h"
# include "GHOST_SystemCocoa.hh"
#else
# include "GHOST_SystemX11.h"
# include "GHOST_SystemX11.hh"
# ifdef WITH_GHOST_WAYLAND
# include "GHOST_SystemWayland.h"
# include "GHOST_SystemWayland.hh"
# else
# define wl_surface void
# define wl_display void

View File

@ -7,7 +7,7 @@
* Definition of GHOST_ContextWGL class.
*/
#include "GHOST_ContextWGL.h"
#include "GHOST_ContextWGL.hh"
#include <tchar.h>

View File

@ -9,7 +9,7 @@
//#define WIN32_COMPOSITING
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
#include <epoxy/wgl.h>

View File

@ -9,8 +9,8 @@
* Copyright (C) 2001 NaN Technologies B.V.
*/
#include "GHOST_DisplayManager.h"
#include "GHOST_Debug.h"
#include "GHOST_DisplayManager.hh"
#include "GHOST_Debug.hh"
GHOST_DisplayManager::GHOST_DisplayManager() : m_settingsInitialized(false) {}

View File

@ -12,7 +12,7 @@
# error Apple only!
#endif // __APPLE__
#include "GHOST_DisplayManager.h"
#include "GHOST_DisplayManager.hh"
/**
* Manages system displays (Mac OSX/Cocoa implementation).

View File

@ -3,8 +3,8 @@
#include <Cocoa/Cocoa.h>
#include "GHOST_Debug.h"
#include "GHOST_DisplayManagerCocoa.h"
#include "GHOST_Debug.hh"
#include "GHOST_DisplayManagerCocoa.hh"
// We do not support multiple monitors at the moment

View File

@ -7,8 +7,8 @@
#pragma once
#include "GHOST_DisplayManager.h"
#include "GHOST_SystemHeadless.h"
#include "GHOST_DisplayManager.hh"
#include "GHOST_SystemHeadless.hh"
class GHOST_SystemHeadless;

View File

@ -8,10 +8,10 @@
* \ingroup GHOST
*/
#include "GHOST_DisplayManagerSDL.h"
#include "GHOST_SystemSDL.h"
#include "GHOST_DisplayManagerSDL.hh"
#include "GHOST_SystemSDL.hh"
#include "GHOST_WindowManager.h"
#include "GHOST_WindowManager.hh"
GHOST_DisplayManagerSDL::GHOST_DisplayManagerSDL(GHOST_SystemSDL *system)
: GHOST_DisplayManager(), m_system(system)

View File

@ -7,7 +7,7 @@
#pragma once
#include "GHOST_DisplayManager.h"
#include "GHOST_DisplayManager.hh"
extern "C" {
#include "SDL.h"

View File

@ -5,8 +5,8 @@
* \ingroup GHOST
*/
#include "GHOST_DisplayManagerWin32.h"
#include "GHOST_Debug.h"
#include "GHOST_DisplayManagerWin32.hh"
#include "GHOST_Debug.hh"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

View File

@ -12,7 +12,7 @@
# error WIN32 only!
#endif // WIN32
#include "GHOST_DisplayManager.h"
#include "GHOST_DisplayManager.hh"
/**
* Manages system displays (WIN32 implementation).

View File

@ -14,8 +14,8 @@
# include <X11/extensions/xf86vmode.h>
#endif
#include "GHOST_DisplayManagerX11.h"
#include "GHOST_SystemX11.h"
#include "GHOST_DisplayManagerX11.hh"
#include "GHOST_SystemX11.hh"
GHOST_DisplayManagerX11::GHOST_DisplayManagerX11(GHOST_SystemX11 *system)
: GHOST_DisplayManager(), m_system(system)

View File

@ -8,7 +8,7 @@
#pragma once
#include "GHOST_DisplayManager.h"
#include "GHOST_DisplayManager.hh"
class GHOST_SystemX11;

View File

@ -5,8 +5,8 @@
* \ingroup GHOST
*/
#include "GHOST_DropTargetWin32.h"
#include "GHOST_Debug.h"
#include "GHOST_DropTargetWin32.hh"
#include "GHOST_Debug.hh"
#include <shellapi.h>
#include "utf_winfunc.h"

View File

@ -7,8 +7,8 @@
#pragma once
#include "GHOST_SystemWin32.h"
#include "GHOST_WindowWin32.h"
#include "GHOST_SystemWin32.hh"
#include "GHOST_WindowWin32.hh"
#include <GHOST_Types.h>
#include <string.h>

View File

@ -5,10 +5,10 @@
* \ingroup GHOST
*/
#include "GHOST_DropTargetX11.h"
#include "GHOST_Debug.h"
#include "GHOST_PathUtils.h"
#include "GHOST_utildefines.h"
#include "GHOST_DropTargetX11.hh"
#include "GHOST_Debug.hh"
#include "GHOST_PathUtils.hh"
#include "GHOST_utildefines.hh"
#include <cassert>
#include <cctype>

View File

@ -7,8 +7,8 @@
#pragma once
#include "GHOST_SystemX11.h"
#include "GHOST_WindowX11.h"
#include "GHOST_SystemX11.hh"
#include "GHOST_WindowX11.hh"
#include <GHOST_Types.h>
#include "xdnd.h"

Some files were not shown because too many files have changed in this diff Show More