Compare commits
491 Commits
temp-geome
...
soc-2021-u
Author | SHA1 | Date | |
---|---|---|---|
560e015a5b | |||
f87ed1547c | |||
1b9dd08d02 | |||
9f6313498a | |||
![]() |
f7a492d460 | ||
a6f6c421ef | |||
f7f5024c95 | |||
9add7c35cc | |||
2526a355bc | |||
7633548d60 | |||
2884ae971a | |||
90b485845c | |||
ba313f8a74 | |||
719451f840 | |||
c0f55400eb | |||
c75e6bcea2 | |||
![]() |
0c59386110 | ||
![]() |
4c156cba21 | ||
3fa6426392 | |||
4d66cbd140 | |||
77061a5621 | |||
4d881d9dad | |||
41e3bf8a8e | |||
8324ac8457 | |||
af95542df3 | |||
6d162d35e2 | |||
![]() |
29e3545194 | ||
05ce5276db | |||
4d51af68ad | |||
29b13fa3ca | |||
499dbb626a | |||
b37d36a60f | |||
3642e17428 | |||
fde9c3bc74 | |||
66dbe6e55a | |||
3c1e75a230 | |||
2df7d1ebce | |||
49ab38bf54 | |||
![]() |
2e6a735385 | ||
84f98e28e3 | |||
33955231f3 | |||
a25cd206c6 | |||
![]() |
96027b2d15 | ||
0803119725 | |||
fa6b1007ba | |||
69928307c5 | |||
![]() |
997b5fe45d | ||
fa2c1698b0 | |||
26f9b1ef49 | |||
f5c6029cc5 | |||
8b8a678cdf | |||
c9d9bfa84a | |||
52bfa750e7 | |||
5eb505e368 | |||
17021adcea | |||
9e939a614e | |||
4472a11017 | |||
![]() |
05f3f11d55 | ||
13a4bccdb1 | |||
15471d9bed | |||
e43ecca016 | |||
3b8d702a2f | |||
32a4c7f188 | |||
a79c33e8f8 | |||
7cb65e4581 | |||
9642447faf | |||
c5c189a158 | |||
eaad219ee7 | |||
da4796ebf7 | |||
fc4f82d200 | |||
8c7c4549d1 | |||
11e11c41f2 | |||
7da9da2b27 | |||
029d042e85 | |||
07b482c2ff | |||
1e3c5fdb85 | |||
4eba920d15 | |||
1f51672d71 | |||
738f1dbeff | |||
c5c8c68eec | |||
c773443845 | |||
f973e0b75a | |||
c9e835fec1 | |||
25aa943e8c | |||
276eebb274 | |||
f256bfb3e2 | |||
942c471ce9 | |||
257c7753e9 | |||
69697fcca9 | |||
25e548c96b | |||
bdbc7e12a0 | |||
970c928f27 | |||
2618df7d03 | |||
136e357d8d | |||
a229a9dd64 | |||
6cf734a2e5 | |||
6b0aa7ae15 | |||
9566e3bc9c | |||
8ee7f62a63 | |||
365443412c | |||
![]() |
9a41b44197 | ||
e1d7ce005f | |||
1cd20b0026 | |||
9dee0a10c8 | |||
06ac655b8d | |||
6dca61b91c | |||
8bc27c508a | |||
f8b51f702c | |||
180bafe225 | |||
da2ba40268 | |||
633c29fb7b | |||
8e21d528ca | |||
4fa0bbb5ac | |||
a1c65748c4 | |||
8e2e44b58b | |||
7a9cfd08a8 | |||
db7fca3588 | |||
f81bacd6f0 | |||
ddb7cb7e4a | |||
31a0708cb1 | |||
58043c0637 | |||
c9daab7936 | |||
73ed076489 | |||
867e6ffe88 | |||
f2cfad77f9 | |||
9fee59a484 | |||
c938d9a0e5 | |||
08aa0eb15d | |||
e97653ccf3 | |||
3deb56424f | |||
e04a10adab | |||
27b6636c45 | |||
4ec2bdbbda | |||
1d5cc52ef6 | |||
1fce66190a | |||
236a9f0814 | |||
4f38624bf5 | |||
95c2f0bea8 | |||
bfe8f29baf | |||
860a55d8fc | |||
0e329a967e | |||
0530b67909 | |||
289f68588a | |||
28bd74c186 | |||
8c5d9fa929 | |||
525def99bc | |||
acb8909021 | |||
![]() |
231948f33f | ||
a866a32ff2 | |||
4a009b54bc | |||
51f7d24a4e | |||
b6d890672c | |||
![]() |
a6adb7ecae | ||
09f14b38f2 | |||
5841f8656d | |||
e456a9de57 | |||
46fff97604 | |||
5c6cc931b2 | |||
1bd28a5e0c | |||
c420399f4d | |||
429136c89f | |||
e6ca054590 | |||
fb27a9bb98 | |||
785e7ddf10 | |||
8cbe55c9e9 | |||
a2c5c2b406 | |||
c1cf66bff3 | |||
202dc3631e | |||
94dd30208e | |||
56f8d7c705 | |||
e1714ce8c9 | |||
97de4f07a3 | |||
e6fa74ffed | |||
![]() |
7c7348f78d | ||
0ed089cebd | |||
3be5ce4aad | |||
cddb792021 | |||
2d13c823ee | |||
edaeec3e72 | |||
dee0b56b92 | |||
426e2663a0 | |||
fd60f6713a | |||
90a48fa064 | |||
1c1be5bdf4 | |||
30845b5c8e | |||
917a972b56 | |||
9b0b78d58f | |||
3ff60bcad8 | |||
9fe6854a93 | |||
![]() |
4f73d43adc | ||
a78410386b | |||
1bcdd1c54e | |||
503d79cd77 | |||
![]() |
6f52ebba19 | ||
c9c890f196 | |||
4b06420e65 | |||
603ae580ce | |||
b777df8080 | |||
410dc76177 | |||
f6ebbfe7de | |||
9d6e960e2c | |||
25550c210a | |||
eaa35b27e0 | |||
9b2b32a333 | |||
9d336576b5 | |||
![]() |
e0394761b9 | ||
b5a1c194c5 | |||
2aa7edbe6b | |||
15405685d9 | |||
b9febb54a4 | |||
c946fdb2e5 | |||
863460e5a5 | |||
cbe05edde5 | |||
4e78b89e48 | |||
166c8be7ac | |||
aeeffb935e | |||
6ae8de4742 | |||
d475f99460 | |||
cb83313863 | |||
![]() |
eab26f1334 | ||
8745bb9628 | |||
6a00e7a428 | |||
5e0684b07d | |||
![]() |
28f773925a | ||
6b7b4f8e57 | |||
e2f99c338b | |||
![]() |
128eb6cbe9 | ||
42215d7cb8 | |||
eb96f0cf06 | |||
0467ff4053 | |||
ca39aff59d | |||
7a5216497c | |||
![]() |
7f1fe10595 | ||
a1167e910a | |||
![]() |
60cfdf0809 | ||
a00507c482 | |||
fe4286435c | |||
93d2940603 | |||
284c9430f9 | |||
![]() |
db6b3801b3 | ||
82ab2c1678 | |||
ee3b4e8420 | |||
c9347b9a7f | |||
f13eb69269 | |||
efcf46fb6d | |||
84d03a1298 | |||
45c44a5b5b | |||
ed4ef77f49 | |||
b4fd8750f9 | |||
62ec88eb84 | |||
3eb6569b38 | |||
![]() |
07c6af4136 | ||
fc46035117 | |||
da50cd86a7 | |||
bf47fb40fd | |||
0f6be4e152 | |||
0c0e5a8420 | |||
f8ead736a0 | |||
9bb99532a5 | |||
b813648378 | |||
3da09f4e29 | |||
bda9e4238a | |||
c8f80453d5 | |||
f9ebd17b4b | |||
df65103bf0 | |||
a131e3bec7 | |||
4e91cd5c11 | |||
8f785524ae | |||
5bfc3a3421 | |||
6fc94d1848 | |||
6bc6ffc35c | |||
96ef184377 | |||
ba5d9fa275 | |||
b5f2b81751 | |||
60e9fb9929 | |||
![]() |
2b2d427bba | ||
![]() |
54f5c174a8 | ||
8d40d61af0 | |||
7beb4a0e0a | |||
1680c3d510 | |||
e6a1d488ab | |||
4abbf6d82b | |||
![]() |
adbafe3b43 | ||
a392609ab6 | |||
73ef2fc2f4 | |||
08acbdc1ff | |||
2b4afcbb4c | |||
c2ce68a018 | |||
8cc3d2d6f5 | |||
d7d8eb7de4 | |||
08593e46a3 | |||
3b1a16833b | |||
5a9a16334c | |||
d9ad77fa58 | |||
bd79d6067c | |||
ce71357711 | |||
![]() |
5a02d0da7a | ||
3e23af4c49 | |||
a3ca973dec | |||
861b7071a2 | |||
![]() |
5eed7cdc8c | ||
e2bbb5b07e | |||
4d0497bea4 | |||
4f0ec3cea5 | |||
687f70ceca | |||
a0912ff566 | |||
49f1695ed0 | |||
81978594a8 | |||
b4c9f88cbe | |||
3e44592cb9 | |||
58632a7f3c | |||
91bca410c0 | |||
bf0ac711fd | |||
![]() |
4ddad5a7ee | ||
![]() |
d10ea97053 | ||
b7718bbdf5 | |||
079bd11556 | |||
b225a7c470 | |||
d84c79a218 | |||
9d7cb5c4a1 | |||
9290b41381 | |||
![]() |
54b72fe9ff | ||
![]() |
c23b6596b9 | ||
![]() |
863d806526 | ||
e6194e7357 | |||
716682365c | |||
4fb7217043 | |||
235655ee0d | |||
a45dd52cf0 | |||
![]() |
ac97893dfc | ||
ae334532cf | |||
f9ccd26b03 | |||
0950cfd9d5 | |||
f530b43550 | |||
d97fd305a0 | |||
671640b4c7 | |||
![]() |
684500837d | ||
4a3243f311 | |||
6fc92b296f | |||
8849bed671 | |||
546314fc96 | |||
799a2b07ad | |||
a8739ae6c2 | |||
a2f3aca647 | |||
19e1b5c1fd | |||
0708733c46 | |||
809b33b69a | |||
![]() |
0ccbf50694 | ||
4170668776 | |||
f77de678d8 | |||
011d3a95e0 | |||
6c177838f3 | |||
baee000001 | |||
f8dd0d0dba | |||
42546db490 | |||
99c981fd06 | |||
083a8921ec | |||
f62eb8ac16 | |||
2aad8fc7bc | |||
7ec839adfa | |||
79281336c0 | |||
8355e3fc77 | |||
e04631f44a | |||
93c6b12df5 | |||
0c5f6f9fa7 | |||
18a4e5d561 | |||
89fa9aada5 | |||
1730829592 | |||
5352b33598 | |||
2914ec571e | |||
f1cdd49a4e | |||
90dac47717 | |||
838b6ec48a | |||
60fba8202c | |||
cfc674408e | |||
596f1878b6 | |||
37943b00f2 | |||
99b1e8428d | |||
b18122451f | |||
84f826ff23 | |||
1be598ba68 | |||
6931a6f3bd | |||
63dc286b01 | |||
a18d88213f | |||
3abf56db27 | |||
9ab31b53b7 | |||
a7ee49d065 | |||
b0cb0a7854 | |||
3b2a01edf6 | |||
d8b445e728 | |||
af7233368d | |||
f6d133e2d2 | |||
f4eacad48f | |||
1f0d63b9a1 | |||
8e00db4296 | |||
fa4a35d4c4 | |||
fa4f9292e1 | |||
d718d6b449 | |||
29590eec6e | |||
c758b87c5e | |||
ea575744b8 | |||
63a5f723d6 | |||
3e4d720ae4 | |||
aabe6e3b45 | |||
65739ded54 | |||
b08ab49cce | |||
bd67bf4d10 | |||
1541fbb4a0 | |||
d374ff5b8f | |||
fbcb9c5e3f | |||
c84d1ad3db | |||
0a8f53a7b8 | |||
b7cb7b78a8 | |||
af3f744b41 | |||
0c2bc843f5 | |||
98deceb5c1 | |||
da8963af2d | |||
72ee339710 | |||
1c74abfa4b | |||
f6e594f1ee | |||
8c3128baae | |||
798214c1f6 | |||
e981df9fbd | |||
112a532f41 | |||
aa0b05ef70 | |||
c3e996a118 | |||
c7a2086253 | |||
0ac3da0e45 | |||
![]() |
a39edbfb19 | ||
e6a68e9511 | |||
1ea018eb4d | |||
08697cff10 | |||
395056561b | |||
6669c559e3 | |||
cacfdcd041 | |||
4362228562 | |||
4ea6595af0 | |||
8506edc0b8 | |||
5c4bd878a2 | |||
![]() |
ccf4103c1a | ||
76e4ffdb90 | |||
97f82a2224 | |||
2581039d55 | |||
1e6fef3aa1 | |||
446f488685 | |||
91a2f5583e | |||
![]() |
aa33073004 | ||
![]() |
bb5373ad7b | ||
![]() |
791cb92b96 | ||
3f0d85de05 | |||
506a2f43b6 | |||
1f13ff614d | |||
c6e1b2f015 | |||
790c6740dc | |||
16cd543e4f | |||
![]() |
f36013a78d | ||
11ef414ba3 | |||
39df796ec9 | |||
e17731fc9c | |||
65c36dc583 | |||
8804c698eb | |||
d6ddacabc1 | |||
9974edc857 | |||
7d5ed35602 | |||
cd75125c48 | |||
e1abd5947f | |||
8d642bbba6 | |||
5777ec9af9 | |||
86023928ba | |||
708f375f76 | |||
28c85e60cb | |||
d615f4d65e | |||
eb88ce5146 | |||
1f65001cae | |||
8a57e48a8f | |||
be270d8c8a | |||
39aa006260 | |||
1965df11f4 | |||
ad5983895a | |||
37e185980a | |||
7e1e4889c6 | |||
62d2e8130f | |||
2b37edebdf | |||
e5ab28d392 | |||
2771b931b5 | |||
f76eca3af2 | |||
279a67ecc8 | |||
1a89001151 | |||
2126fc815d | |||
790d11899a | |||
6a422b6624 |
@@ -403,7 +403,7 @@ option(WITH_CYCLES_CUDA_BINARIES "Build Cycles CUDA binaries" OFF)
|
||||
option(WITH_CYCLES_CUBIN_COMPILER "Build cubins with nvrtc based compiler instead of nvcc" OFF)
|
||||
option(WITH_CYCLES_CUDA_BUILD_SERIAL "Build cubins one after another (useful on machines with limited RAM)" OFF)
|
||||
mark_as_advanced(WITH_CYCLES_CUDA_BUILD_SERIAL)
|
||||
set(CYCLES_TEST_DEVICES CPU CACHE STRING "Run regression tests on the specified device types (CPU CUDA OPTIX OPENCL)" )
|
||||
set(CYCLES_TEST_DEVICES CPU CACHE STRING "Run regression tests on the specified device types (CPU CUDA OPTIX)" )
|
||||
set(CYCLES_CUDA_BINARIES_ARCH sm_30 sm_35 sm_37 sm_50 sm_52 sm_60 sm_61 sm_70 sm_75 sm_86 compute_75 CACHE STRING "CUDA architectures to build binaries for")
|
||||
mark_as_advanced(CYCLES_CUDA_BINARIES_ARCH)
|
||||
unset(PLATFORM_DEFAULT)
|
||||
@@ -418,12 +418,8 @@ mark_as_advanced(WITH_CYCLES_DEBUG_NAN)
|
||||
mark_as_advanced(WITH_CYCLES_NATIVE_ONLY)
|
||||
|
||||
option(WITH_CYCLES_DEVICE_CUDA "Enable Cycles CUDA compute support" ON)
|
||||
option(WITH_CYCLES_DEVICE_OPTIX "Enable Cycles OptiX support" OFF)
|
||||
option(WITH_CYCLES_DEVICE_OPENCL "Enable Cycles OpenCL compute support" ON)
|
||||
option(WITH_CYCLES_NETWORK "Enable Cycles compute over network support (EXPERIMENTAL and unfinished)" OFF)
|
||||
option(WITH_CYCLES_DEVICE_OPTIX "Enable Cycles OptiX support" ON)
|
||||
mark_as_advanced(WITH_CYCLES_DEVICE_CUDA)
|
||||
mark_as_advanced(WITH_CYCLES_DEVICE_OPENCL)
|
||||
mark_as_advanced(WITH_CYCLES_NETWORK)
|
||||
|
||||
option(WITH_CUDA_DYNLOAD "Dynamically load CUDA libraries at runtime" ON)
|
||||
mark_as_advanced(WITH_CUDA_DYNLOAD)
|
||||
|
@@ -33,11 +33,23 @@ FIND_PATH(OPTIX_INCLUDE_DIR
|
||||
include
|
||||
)
|
||||
|
||||
IF(EXISTS "${OPTIX_INCLUDE_DIR}/optix.h")
|
||||
FILE(STRINGS "${OPTIX_INCLUDE_DIR}/optix.h" _optix_version REGEX "^#define OPTIX_VERSION[ \t].*$")
|
||||
STRING(REGEX MATCHALL "[0-9]+" _optix_version ${_optix_version})
|
||||
|
||||
MATH(EXPR _optix_version_major "${_optix_version} / 10000")
|
||||
MATH(EXPR _optix_version_minor "(${_optix_version} % 10000) / 100")
|
||||
MATH(EXPR _optix_version_patch "${_optix_version} % 100")
|
||||
|
||||
SET(OPTIX_VERSION "${_optix_version_major}.${_optix_version_minor}.${_optix_version_patch}")
|
||||
ENDIF()
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set OPTIX_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OptiX DEFAULT_MSG
|
||||
OPTIX_INCLUDE_DIR)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OptiX
|
||||
REQUIRED_VARS OPTIX_INCLUDE_DIR
|
||||
VERSION_VAR OPTIX_VERSION)
|
||||
|
||||
IF(OPTIX_FOUND)
|
||||
SET(OPTIX_INCLUDE_DIRS ${OPTIX_INCLUDE_DIR})
|
||||
@@ -45,6 +57,7 @@ ENDIF()
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
OPTIX_INCLUDE_DIR
|
||||
OPTIX_VERSION
|
||||
)
|
||||
|
||||
UNSET(_optix_SEARCH_DIRS)
|
||||
|
@@ -259,7 +259,7 @@ if(NOT DEFINED LIBDIR)
|
||||
else()
|
||||
message(FATAL_ERROR "32 bit compiler detected, blender no longer provides pre-build libraries for 32 bit windows, please set the LIBDIR cmake variable to your own library folder")
|
||||
endif()
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.29.30130)
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.30.30423)
|
||||
message(STATUS "Visual Studio 2022 detected.")
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc15)
|
||||
elseif(MSVC_VERSION GREATER 1919)
|
||||
|
@@ -55,7 +55,7 @@ buildbot:
|
||||
cuda11:
|
||||
version: '11.4.1'
|
||||
optix:
|
||||
version: '7.1.0'
|
||||
version: '7.3.0'
|
||||
cmake:
|
||||
default:
|
||||
version: any
|
||||
|
@@ -31,6 +31,7 @@ def parse_arguments():
|
||||
parser.add_argument("--no-submodules", action="store_true")
|
||||
parser.add_argument("--use-tests", action="store_true")
|
||||
parser.add_argument("--svn-command", default="svn")
|
||||
parser.add_argument("--svn-branch", default=None)
|
||||
parser.add_argument("--git-command", default="git")
|
||||
parser.add_argument("--use-centos-libraries", action="store_true")
|
||||
return parser.parse_args()
|
||||
@@ -46,7 +47,7 @@ def svn_update(args, release_version):
|
||||
svn_non_interactive = [args.svn_command, '--non-interactive']
|
||||
|
||||
lib_dirpath = os.path.join(get_blender_git_root(), '..', 'lib')
|
||||
svn_url = make_utils.svn_libraries_base_url(release_version)
|
||||
svn_url = make_utils.svn_libraries_base_url(release_version, args.svn_branch)
|
||||
|
||||
# Checkout precompiled libraries
|
||||
if sys.platform == 'darwin':
|
||||
@@ -170,26 +171,28 @@ def submodules_update(args, release_version, branch):
|
||||
sys.stderr.write("git not found, can't update code\n")
|
||||
sys.exit(1)
|
||||
|
||||
# Update submodules to latest master or appropriate release branch.
|
||||
if not release_version:
|
||||
branch = "master"
|
||||
# Update submodules to appropriate given branch,
|
||||
# falling back to master if none is given and/or found in a sub-repository.
|
||||
branch_fallback = "master"
|
||||
if not branch:
|
||||
branch = branch_fallback
|
||||
|
||||
submodules = [
|
||||
("release/scripts/addons", branch),
|
||||
("release/scripts/addons_contrib", branch),
|
||||
("release/datafiles/locale", branch),
|
||||
("source/tools", branch),
|
||||
("release/scripts/addons", branch, branch_fallback),
|
||||
("release/scripts/addons_contrib", branch, branch_fallback),
|
||||
("release/datafiles/locale", branch, branch_fallback),
|
||||
("source/tools", branch, branch_fallback),
|
||||
]
|
||||
|
||||
# Initialize submodules only if needed.
|
||||
for submodule_path, submodule_branch in submodules:
|
||||
for submodule_path, submodule_branch, submodule_branch_fallback in submodules:
|
||||
if not os.path.exists(os.path.join(submodule_path, ".git")):
|
||||
call([args.git_command, "submodule", "update", "--init", "--recursive"])
|
||||
break
|
||||
|
||||
# Checkout appropriate branch and pull changes.
|
||||
skip_msg = ""
|
||||
for submodule_path, submodule_branch in submodules:
|
||||
for submodule_path, submodule_branch, submodule_branch_fallback in submodules:
|
||||
cwd = os.getcwd()
|
||||
try:
|
||||
os.chdir(submodule_path)
|
||||
@@ -197,10 +200,20 @@ def submodules_update(args, release_version, branch):
|
||||
if msg:
|
||||
skip_msg += submodule_path + " skipped: " + msg + "\n"
|
||||
else:
|
||||
if make_utils.git_branch(args.git_command) != submodule_branch:
|
||||
call([args.git_command, "fetch", "origin"])
|
||||
call([args.git_command, "checkout", submodule_branch])
|
||||
call([args.git_command, "pull", "--rebase", "origin", submodule_branch])
|
||||
# Find a matching branch that exists.
|
||||
call([args.git_command, "fetch", "origin"])
|
||||
if make_utils.git_branch_exists(args.git_command, submodule_branch):
|
||||
pass
|
||||
elif make_utils.git_branch_exists(args.git_command, submodule_branch_fallback):
|
||||
submodule_branch = submodule_branch_fallback
|
||||
else:
|
||||
submodule_branch = None
|
||||
|
||||
# Switch to branch and pull.
|
||||
if submodule_branch:
|
||||
if make_utils.git_branch(args.git_command) != submodule_branch:
|
||||
call([args.git_command, "checkout", submodule_branch])
|
||||
call([args.git_command, "pull", "--rebase", "origin", submodule_branch])
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
|
||||
@@ -214,6 +227,10 @@ if __name__ == "__main__":
|
||||
|
||||
# Test if we are building a specific release version.
|
||||
branch = make_utils.git_branch(args.git_command)
|
||||
if branch == 'HEAD':
|
||||
sys.stderr.write('Blender git repository is in detached HEAD state, must be in a branch\n')
|
||||
sys.exit(1)
|
||||
|
||||
tag = make_utils.git_tag(args.git_command)
|
||||
release_version = make_utils.git_branch_release_version(branch, tag)
|
||||
|
||||
|
@@ -8,14 +8,19 @@ import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def call(cmd, exit_on_error=True):
|
||||
print(" ".join(cmd))
|
||||
def call(cmd, exit_on_error=True, silent=False):
|
||||
if not silent:
|
||||
print(" ".join(cmd))
|
||||
|
||||
# Flush to ensure correct order output on Windows.
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
|
||||
retcode = subprocess.call(cmd)
|
||||
if silent:
|
||||
retcode = subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
else:
|
||||
retcode = subprocess.call(cmd)
|
||||
|
||||
if exit_on_error and retcode != 0:
|
||||
sys.exit(retcode)
|
||||
return retcode
|
||||
@@ -38,6 +43,11 @@ def check_output(cmd, exit_on_error=True):
|
||||
return output.strip()
|
||||
|
||||
|
||||
def git_branch_exists(git_command, branch):
|
||||
return call([git_command, "rev-parse", "--verify", branch], exit_on_error=False, silent=True) == 0 or \
|
||||
call([git_command, "rev-parse", "--verify", "remotes/origin/" + branch], exit_on_error=False, silent=True) == 0
|
||||
|
||||
|
||||
def git_branch(git_command):
|
||||
# Get current branch name.
|
||||
try:
|
||||
@@ -70,9 +80,11 @@ def git_branch_release_version(branch, tag):
|
||||
return release_version
|
||||
|
||||
|
||||
def svn_libraries_base_url(release_version):
|
||||
def svn_libraries_base_url(release_version, branch=None):
|
||||
if release_version:
|
||||
svn_branch = "tags/blender-" + release_version + "-release"
|
||||
elif branch:
|
||||
svn_branch = "branches/" + branch
|
||||
else:
|
||||
svn_branch = "trunk"
|
||||
return "https://svn.blender.org/svnroot/bf-blender/" + svn_branch + "/lib/"
|
||||
|
@@ -1,4 +1,4 @@
|
||||
if EXIST %PYTHON% (
|
||||
if EXIST "%PYTHON%" (
|
||||
goto detect_python_done
|
||||
)
|
||||
|
||||
|
@@ -14,7 +14,7 @@ sound = aud.Sound('music.ogg')
|
||||
# play the audio, this return a handle to control play/pause
|
||||
handle = device.play(sound)
|
||||
# if the audio is not too big and will be used often you can buffer it
|
||||
sound_buffered = aud.Sound.buffer(sound)
|
||||
sound_buffered = aud.Sound.cache(sound)
|
||||
handle_buffered = device.play(sound_buffered)
|
||||
|
||||
# stop the sounds (otherwise they play until their ends)
|
||||
|
@@ -10,4 +10,4 @@ requests==2.26.0
|
||||
|
||||
# Only needed to match the theme used for the official documentation.
|
||||
# Without this theme, the default theme will be used.
|
||||
sphinx_rtd_theme==1.0.0rc1
|
||||
sphinx_rtd_theme==1.0.0
|
||||
|
@@ -1039,13 +1039,17 @@ context_type_map = {
|
||||
# context_member: (RNA type, is_collection)
|
||||
"active_annotation_layer": ("GPencilLayer", False),
|
||||
"active_bone": ("EditBone", False),
|
||||
"active_file": ("FileSelectEntry", False),
|
||||
"active_gpencil_frame": ("GreasePencilLayer", True),
|
||||
"active_gpencil_layer": ("GPencilLayer", True),
|
||||
"active_node": ("Node", False),
|
||||
"active_object": ("Object", False),
|
||||
"active_operator": ("Operator", False),
|
||||
"active_pose_bone": ("PoseBone", False),
|
||||
"active_sequence_strip": ("Sequence", False),
|
||||
"active_editable_fcurve": ("FCurve", False),
|
||||
"active_nla_strip": ("NlaStrip", False),
|
||||
"active_nla_track": ("NlaTrack", False),
|
||||
"annotation_data": ("GreasePencil", False),
|
||||
"annotation_data_owner": ("ID", False),
|
||||
"armature": ("Armature", False),
|
||||
@@ -1074,6 +1078,7 @@ context_type_map = {
|
||||
"gpencil_data": ("GreasePencil", False),
|
||||
"gpencil_data_owner": ("ID", False),
|
||||
"hair": ("Hair", False),
|
||||
"id": ("ID", False),
|
||||
"image_paint_object": ("Object", False),
|
||||
"lattice": ("Lattice", False),
|
||||
"light": ("Light", False),
|
||||
@@ -1102,6 +1107,7 @@ context_type_map = {
|
||||
"selected_editable_keyframes": ("Keyframe", True),
|
||||
"selected_editable_objects": ("Object", True),
|
||||
"selected_editable_sequences": ("Sequence", True),
|
||||
"selected_files": ("FileSelectEntry", True),
|
||||
"selected_nla_strips": ("NlaStrip", True),
|
||||
"selected_nodes": ("Node", True),
|
||||
"selected_objects": ("Object", True),
|
||||
@@ -1198,6 +1204,7 @@ def pycontext2sphinx(basepath):
|
||||
"text_context_dir",
|
||||
"clip_context_dir",
|
||||
"sequencer_context_dir",
|
||||
"file_context_dir",
|
||||
)
|
||||
|
||||
unique = set()
|
||||
|
8
extern/audaspace/CMakeLists.txt
vendored
8
extern/audaspace/CMakeLists.txt
vendored
@@ -129,6 +129,7 @@ set(SRC
|
||||
src/util/Barrier.cpp
|
||||
src/util/Buffer.cpp
|
||||
src/util/BufferReader.cpp
|
||||
src/util/RingBuffer.cpp
|
||||
src/util/StreamBuffer.cpp
|
||||
src/util/ThreadPool.cpp
|
||||
)
|
||||
@@ -152,6 +153,7 @@ set(PUBLIC_HDR
|
||||
include/devices/ThreadedDevice.h
|
||||
include/Exception.h
|
||||
include/file/File.h
|
||||
include/file/FileInfo.h
|
||||
include/file/FileManager.h
|
||||
include/file/FileWriter.h
|
||||
include/file/IFileInput.h
|
||||
@@ -244,6 +246,7 @@ set(PUBLIC_HDR
|
||||
include/util/BufferReader.h
|
||||
include/util/ILockable.h
|
||||
include/util/Math3D.h
|
||||
include/util/RingBuffer.h
|
||||
include/util/StreamBuffer.h
|
||||
include/util/ThreadPool.h
|
||||
)
|
||||
@@ -960,7 +963,10 @@ endif()
|
||||
if(BUILD_DEMOS)
|
||||
include_directories(${INCLUDE})
|
||||
|
||||
set(DEMOS audaplay audaconvert audaremap signalgen randsounds dynamicmusic playbackmanager)
|
||||
set(DEMOS audainfo audaplay audaconvert audaremap signalgen randsounds dynamicmusic playbackmanager)
|
||||
|
||||
add_executable(audainfo demos/audainfo.cpp)
|
||||
target_link_libraries(audainfo audaspace)
|
||||
|
||||
add_executable(audaplay demos/audaplay.cpp)
|
||||
target_link_libraries(audaplay audaspace)
|
||||
|
@@ -39,7 +39,7 @@ extern AUD_API void AUD_PlaybackManager_free(AUD_PlaybackManager* manager);
|
||||
* Plays a sound through the playback manager, adding it into a category.
|
||||
* \param manager The PlaybackManager object.
|
||||
* \param sound The sound to be played.
|
||||
* \param catKey The key of the category into which the sound will be added. If it doesn't exist a new one will be creatd.
|
||||
* \param catKey The key of the category into which the sound will be added. If it doesn't exist a new one will be created.
|
||||
*/
|
||||
extern AUD_API void AUD_PlaybackManager_play(AUD_PlaybackManager* manager, AUD_Sound* sound, unsigned int catKey);
|
||||
|
||||
|
42
extern/audaspace/bindings/C/AUD_Sound.cpp
vendored
42
extern/audaspace/bindings/C/AUD_Sound.cpp
vendored
@@ -94,6 +94,36 @@ AUD_API int AUD_Sound_getLength(AUD_Sound* sound)
|
||||
return (*sound)->createReader()->getLength();
|
||||
}
|
||||
|
||||
AUD_API int AUD_Sound_getFileStreams(AUD_Sound* sound, AUD_StreamInfo **stream_infos)
|
||||
{
|
||||
assert(sound);
|
||||
|
||||
std::shared_ptr<File> file = std::dynamic_pointer_cast<File>(*sound);
|
||||
|
||||
if(file)
|
||||
{
|
||||
auto streams = file->queryStreams();
|
||||
|
||||
size_t size = sizeof(AUD_StreamInfo) * streams.size();
|
||||
|
||||
if(!size)
|
||||
{
|
||||
*stream_infos = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*stream_infos = reinterpret_cast<AUD_StreamInfo*>(std::malloc(size));
|
||||
std::memcpy(*stream_infos, streams.data(), size);
|
||||
|
||||
return streams.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
*stream_infos = nullptr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
AUD_API sample_t* AUD_Sound_data(AUD_Sound* sound, int* length, AUD_Specs* specs)
|
||||
{
|
||||
assert(sound);
|
||||
@@ -252,6 +282,12 @@ AUD_API AUD_Sound* AUD_Sound_bufferFile(unsigned char* buffer, int size)
|
||||
return new AUD_Sound(new File(buffer, size));
|
||||
}
|
||||
|
||||
AUD_API AUD_Sound* AUD_Sound_bufferFileStream(unsigned char* buffer, int size, int stream)
|
||||
{
|
||||
assert(buffer);
|
||||
return new AUD_Sound(new File(buffer, size, stream));
|
||||
}
|
||||
|
||||
AUD_API AUD_Sound* AUD_Sound_cache(AUD_Sound* sound)
|
||||
{
|
||||
assert(sound);
|
||||
@@ -272,6 +308,12 @@ AUD_API AUD_Sound* AUD_Sound_file(const char* filename)
|
||||
return new AUD_Sound(new File(filename));
|
||||
}
|
||||
|
||||
AUD_API AUD_Sound* AUD_Sound_fileStream(const char* filename, int stream)
|
||||
{
|
||||
assert(filename);
|
||||
return new AUD_Sound(new File(filename, stream));
|
||||
}
|
||||
|
||||
AUD_API AUD_Sound* AUD_Sound_sawtooth(float frequency, AUD_SampleRate rate)
|
||||
{
|
||||
return new AUD_Sound(new Sawtooth(frequency, rate));
|
||||
|
27
extern/audaspace/bindings/C/AUD_Sound.h
vendored
27
extern/audaspace/bindings/C/AUD_Sound.h
vendored
@@ -36,7 +36,15 @@ extern AUD_API AUD_Specs AUD_Sound_getSpecs(AUD_Sound* sound);
|
||||
* \return The length of the sound in samples.
|
||||
* \note This function creates a reader from the sound and deletes it again.
|
||||
*/
|
||||
extern AUD_API int AUD_getLength(AUD_Sound* sound);
|
||||
extern AUD_API int AUD_Sound_getLength(AUD_Sound* sound);
|
||||
|
||||
/**
|
||||
* Retrieves the stream infos of a sound file.
|
||||
* \param sound The sound to retrieve from which must be a file sound.
|
||||
* \param infos A pointer to a AUD_StreamInfo array that will be allocated and must afterwards be freed by the caller.
|
||||
* \return The number of items in the infos array.
|
||||
*/
|
||||
extern AUD_API int AUD_Sound_getFileStreams(AUD_Sound* sound, AUD_StreamInfo** stream_infos);
|
||||
|
||||
/**
|
||||
* Reads a sound's samples into memory.
|
||||
@@ -89,6 +97,15 @@ extern AUD_API AUD_Sound* AUD_Sound_buffer(sample_t* data, int length, AUD_Specs
|
||||
*/
|
||||
extern AUD_API AUD_Sound* AUD_Sound_bufferFile(unsigned char* buffer, int size);
|
||||
|
||||
/**
|
||||
* Loads a sound file from a memory buffer.
|
||||
* \param buffer The buffer which contains the sound file.
|
||||
* \param size The size of the buffer.
|
||||
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
|
||||
* \return A handle of the sound file.
|
||||
*/
|
||||
extern AUD_API AUD_Sound* AUD_Sound_bufferFileStream(unsigned char* buffer, int size, int stream);
|
||||
|
||||
/**
|
||||
* Caches a sound into a memory buffer.
|
||||
* \param sound The sound to cache.
|
||||
@@ -103,6 +120,14 @@ extern AUD_API AUD_Sound* AUD_Sound_cache(AUD_Sound* sound);
|
||||
*/
|
||||
extern AUD_API AUD_Sound* AUD_Sound_file(const char* filename);
|
||||
|
||||
/**
|
||||
* Loads a sound file.
|
||||
* \param filename The filename of the sound file.
|
||||
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
|
||||
* \return A handle of the sound file.
|
||||
*/
|
||||
extern AUD_API AUD_Sound* AUD_Sound_fileStream(const char* filename, int stream);
|
||||
|
||||
/**
|
||||
* Creates a sawtooth sound.
|
||||
* \param frequency The frequency of the generated sawtooth sound.
|
||||
|
8
extern/audaspace/bindings/C/AUD_Special.cpp
vendored
8
extern/audaspace/bindings/C/AUD_Special.cpp
vendored
@@ -86,7 +86,6 @@ AUD_API AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
|
||||
info.specs.channels = AUD_CHANNELS_INVALID;
|
||||
info.specs.rate = AUD_RATE_INVALID;
|
||||
info.length = 0.0f;
|
||||
info.start_offset = 0.0f;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -96,7 +95,6 @@ AUD_API AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
|
||||
{
|
||||
info.specs = convSpecToC(reader->getSpecs());
|
||||
info.length = reader->getLength() / (float) info.specs.rate;
|
||||
info.start_offset = reader->getStartOffset();
|
||||
}
|
||||
}
|
||||
catch(Exception&)
|
||||
@@ -109,7 +107,7 @@ AUD_API AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
|
||||
AUD_API float* AUD_readSoundBuffer(const char* filename, float low, float high,
|
||||
float attack, float release, float threshold,
|
||||
int accumulate, int additive, int square,
|
||||
float sthreshold, double samplerate, int* length)
|
||||
float sthreshold, double samplerate, int* length, int stream)
|
||||
{
|
||||
Buffer buffer;
|
||||
DeviceSpecs specs;
|
||||
@@ -117,7 +115,7 @@ AUD_API float* AUD_readSoundBuffer(const char* filename, float low, float high,
|
||||
specs.rate = (SampleRate)samplerate;
|
||||
std::shared_ptr<ISound> sound;
|
||||
|
||||
std::shared_ptr<ISound> file = std::shared_ptr<ISound>(new File(filename));
|
||||
std::shared_ptr<ISound> file = std::shared_ptr<ISound>(new File(filename, stream));
|
||||
|
||||
int position = 0;
|
||||
|
||||
@@ -247,7 +245,7 @@ AUD_API int AUD_readSound(AUD_Sound* sound, float* buffer, int length, int sampl
|
||||
|
||||
buffer[i * 3] = min;
|
||||
buffer[i * 3 + 1] = max;
|
||||
buffer[i * 3 + 2] = sqrt(power / len); // RMS
|
||||
buffer[i * 3 + 2] = std::sqrt(power / len);
|
||||
|
||||
if(overallmax < max)
|
||||
overallmax = max;
|
||||
|
2
extern/audaspace/bindings/C/AUD_Special.h
vendored
2
extern/audaspace/bindings/C/AUD_Special.h
vendored
@@ -37,7 +37,7 @@ extern AUD_API float* AUD_readSoundBuffer(const char* filename, float low, float
|
||||
float attack, float release, float threshold,
|
||||
int accumulate, int additive, int square,
|
||||
float sthreshold, double samplerate,
|
||||
int* length);
|
||||
int* length, int stream);
|
||||
|
||||
/**
|
||||
* Pauses a playing sound after a specific amount of time.
|
||||
|
14
extern/audaspace/bindings/C/AUD_Types.h
vendored
14
extern/audaspace/bindings/C/AUD_Types.h
vendored
@@ -176,5 +176,17 @@ typedef struct
|
||||
{
|
||||
AUD_Specs specs;
|
||||
float length;
|
||||
double start_offset;
|
||||
} AUD_SoundInfo;
|
||||
|
||||
/// Specification of a sound source.
|
||||
typedef struct
|
||||
{
|
||||
/// Start time in seconds.
|
||||
double start;
|
||||
|
||||
/// Duration in seconds. May be estimated or 0 if unknown.
|
||||
double duration;
|
||||
|
||||
/// Audio data parameters.
|
||||
AUD_DeviceSpecs specs;
|
||||
} AUD_StreamInfo;
|
||||
|
12
extern/audaspace/bindings/python/PySound.cpp
vendored
12
extern/audaspace/bindings/python/PySound.cpp
vendored
@@ -89,10 +89,11 @@ Sound_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
|
||||
self = (Sound*)type->tp_alloc(type, 0);
|
||||
if(self != nullptr)
|
||||
{
|
||||
static const char* kwlist[] = {"filename", nullptr};
|
||||
static const char* kwlist[] = {"filename", "stream", nullptr};
|
||||
const char* filename = nullptr;
|
||||
int stream = 0;
|
||||
|
||||
if(!PyArg_ParseTupleAndKeywords(args, kwds, "s:Sound", const_cast<char**>(kwlist), &filename))
|
||||
if(!PyArg_ParseTupleAndKeywords(args, kwds, "s|i:Sound", const_cast<char**>(kwlist), &filename, &stream))
|
||||
{
|
||||
Py_DECREF(self);
|
||||
return nullptr;
|
||||
@@ -100,7 +101,7 @@ Sound_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
|
||||
|
||||
try
|
||||
{
|
||||
self->sound = new std::shared_ptr<ISound>(new File(filename));
|
||||
self->sound = new std::shared_ptr<ISound>(new File(filename, stream));
|
||||
}
|
||||
catch(Exception& e)
|
||||
{
|
||||
@@ -407,8 +408,9 @@ static PyObject *
|
||||
Sound_file(PyTypeObject* type, PyObject* args)
|
||||
{
|
||||
const char* filename = nullptr;
|
||||
int stream = 0;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "s:file", &filename))
|
||||
if(!PyArg_ParseTuple(args, "s|i:file", &filename, &stream))
|
||||
return nullptr;
|
||||
|
||||
Sound* self;
|
||||
@@ -418,7 +420,7 @@ Sound_file(PyTypeObject* type, PyObject* args)
|
||||
{
|
||||
try
|
||||
{
|
||||
self->sound = new std::shared_ptr<ISound>(new File(filename));
|
||||
self->sound = new std::shared_ptr<ISound>(new File(filename, stream));
|
||||
}
|
||||
catch(Exception& e)
|
||||
{
|
||||
|
6
extern/audaspace/include/IReader.h
vendored
6
extern/audaspace/include/IReader.h
vendored
@@ -70,12 +70,6 @@ public:
|
||||
*/
|
||||
virtual int getPosition() const=0;
|
||||
|
||||
/**
|
||||
* Returns the start offset the sound should have to line up with related sources.
|
||||
* \return The required start offset in seconds.
|
||||
*/
|
||||
virtual double getStartOffset() const { return 0.0;}
|
||||
|
||||
/**
|
||||
* Returns the specification of the reader.
|
||||
* \return The Specs structure.
|
||||
|
23
extern/audaspace/include/file/File.h
vendored
23
extern/audaspace/include/file/File.h
vendored
@@ -23,9 +23,11 @@
|
||||
*/
|
||||
|
||||
#include "ISound.h"
|
||||
#include "FileInfo.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
AUD_NAMESPACE_BEGIN
|
||||
|
||||
@@ -48,6 +50,14 @@ private:
|
||||
*/
|
||||
std::shared_ptr<Buffer> m_buffer;
|
||||
|
||||
/**
|
||||
* The index of the stream within the file if it contains multiple.
|
||||
* The first audio stream in the file has index 0 and the index increments by one
|
||||
* for every other audio stream in the file. Other types of streams in the file
|
||||
* do not count.
|
||||
*/
|
||||
int m_stream;
|
||||
|
||||
// delete copy constructor and operator=
|
||||
File(const File&) = delete;
|
||||
File& operator=(const File&) = delete;
|
||||
@@ -57,16 +67,25 @@ public:
|
||||
* Creates a new sound.
|
||||
* The file is read from the file system using the given path.
|
||||
* \param filename The sound file path.
|
||||
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
|
||||
*/
|
||||
File(std::string filename);
|
||||
File(std::string filename, int stream = 0);
|
||||
|
||||
/**
|
||||
* Creates a new sound.
|
||||
* The file is read from memory using the supplied buffer.
|
||||
* \param buffer The buffer to read from.
|
||||
* \param size The size of the buffer.
|
||||
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
|
||||
*/
|
||||
File(const data_t* buffer, int size);
|
||||
File(const data_t* buffer, int size, int stream = 0);
|
||||
|
||||
/**
|
||||
* Queries the streams of the file.
|
||||
* \return A vector with as many streams as there are in the file.
|
||||
* \exception Exception Thrown if the file specified cannot be read.
|
||||
*/
|
||||
std::vector<StreamInfo> queryStreams();
|
||||
|
||||
virtual std::shared_ptr<IReader> createReader();
|
||||
};
|
||||
|
42
extern/audaspace/include/file/FileInfo.h
vendored
Normal file
42
extern/audaspace/include/file/FileInfo.h
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/*******************************************************************************
|
||||
* Copyright 2009-2016 Jörg Müller
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file FileInfo.h
|
||||
* @ingroup file
|
||||
* The FileInfo data structures.
|
||||
*/
|
||||
|
||||
#include "respec/Specification.h"
|
||||
|
||||
AUD_NAMESPACE_BEGIN
|
||||
|
||||
/// Specification of a sound source.
|
||||
struct StreamInfo
|
||||
{
|
||||
/// Start time in seconds.
|
||||
double start;
|
||||
|
||||
/// Duration in seconds. May be estimated or 0 if unknown.
|
||||
double duration;
|
||||
|
||||
/// Audio data parameters.
|
||||
DeviceSpecs specs;
|
||||
};
|
||||
|
||||
AUD_NAMESPACE_END
|
24
extern/audaspace/include/file/FileManager.h
vendored
24
extern/audaspace/include/file/FileManager.h
vendored
@@ -22,12 +22,14 @@
|
||||
* The FileManager class.
|
||||
*/
|
||||
|
||||
#include "FileInfo.h"
|
||||
#include "respec/Specification.h"
|
||||
#include "IWriter.h"
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
AUD_NAMESPACE_BEGIN
|
||||
|
||||
@@ -66,18 +68,36 @@ public:
|
||||
/**
|
||||
* Creates a file reader for the given filename if a registed IFileInput is able to read it.
|
||||
* @param filename The path to the file.
|
||||
* @param stream The index of the audio stream within the file if it contains multiple audio streams.
|
||||
* @return The reader created.
|
||||
* @exception Exception If no file input can read the file an exception is thrown.
|
||||
*/
|
||||
static std::shared_ptr<IReader> createReader(std::string filename);
|
||||
static std::shared_ptr<IReader> createReader(std::string filename, int stream = 0);
|
||||
|
||||
/**
|
||||
* Creates a file reader for the given buffer if a registed IFileInput is able to read it.
|
||||
* @param buffer The buffer to read the file from.
|
||||
* @param stream The index of the audio stream within the file if it contains multiple audio streams.
|
||||
* @return The reader created.
|
||||
* @exception Exception If no file input can read the file an exception is thrown.
|
||||
*/
|
||||
static std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer);
|
||||
static std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer, int stream = 0);
|
||||
|
||||
/**
|
||||
* Queries the streams of a sound file.
|
||||
* \param filename Path to the file to be read.
|
||||
* \return A vector with as many streams as there are in the file.
|
||||
* \exception Exception Thrown if the file specified cannot be read.
|
||||
*/
|
||||
static std::vector<StreamInfo> queryStreams(std::string filename);
|
||||
|
||||
/**
|
||||
* Queries the streams of a sound file.
|
||||
* \param buffer The in-memory file buffer.
|
||||
* \return A vector with as many streams as there are in the file.
|
||||
* \exception Exception Thrown if the file specified cannot be read.
|
||||
*/
|
||||
static std::vector<StreamInfo> queryStreams(std::shared_ptr<Buffer> buffer);
|
||||
|
||||
/**
|
||||
* Creates a file writer that writes a sound to the given file path.
|
||||
|
24
extern/audaspace/include/file/IFileInput.h
vendored
24
extern/audaspace/include/file/IFileInput.h
vendored
@@ -23,9 +23,11 @@
|
||||
*/
|
||||
|
||||
#include "Audaspace.h"
|
||||
#include "FileInfo.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
AUD_NAMESPACE_BEGIN
|
||||
|
||||
@@ -48,18 +50,36 @@ public:
|
||||
/**
|
||||
* Creates a reader for a file to be read.
|
||||
* \param filename Path to the file to be read.
|
||||
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
|
||||
* \return The reader that reads the file.
|
||||
* \exception Exception Thrown if the file specified cannot be read.
|
||||
*/
|
||||
virtual std::shared_ptr<IReader> createReader(std::string filename)=0;
|
||||
virtual std::shared_ptr<IReader> createReader(std::string filename, int stream = 0)=0;
|
||||
|
||||
/**
|
||||
* Creates a reader for a file to be read from memory.
|
||||
* \param buffer The in-memory file buffer.
|
||||
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
|
||||
* \return The reader that reads the file.
|
||||
* \exception Exception Thrown if the file specified cannot be read.
|
||||
*/
|
||||
virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer)=0;
|
||||
virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer, int stream = 0)=0;
|
||||
|
||||
/**
|
||||
* Queries the streams of a sound file.
|
||||
* \param filename Path to the file to be read.
|
||||
* \return A vector with as many streams as there are in the file.
|
||||
* \exception Exception Thrown if the file specified cannot be read.
|
||||
*/
|
||||
virtual std::vector<StreamInfo> queryStreams(std::string filename)=0;
|
||||
|
||||
/**
|
||||
* Queries the streams of a sound file.
|
||||
* \param buffer The in-memory file buffer.
|
||||
* \return A vector with as many streams as there are in the file.
|
||||
* \exception Exception Thrown if the file specified cannot be read.
|
||||
*/
|
||||
virtual std::vector<StreamInfo> queryStreams(std::shared_ptr<Buffer> buffer)=0;
|
||||
};
|
||||
|
||||
AUD_NAMESPACE_END
|
||||
|
2
extern/audaspace/include/fx/VolumeReader.h
vendored
2
extern/audaspace/include/fx/VolumeReader.h
vendored
@@ -67,4 +67,4 @@ public:
|
||||
virtual void read(int& length, bool& eos, sample_t* buffer);
|
||||
};
|
||||
|
||||
AUD_NAMESPACE_END
|
||||
AUD_NAMESPACE_END
|
97
extern/audaspace/include/util/RingBuffer.h
vendored
Normal file
97
extern/audaspace/include/util/RingBuffer.h
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
/*******************************************************************************
|
||||
* Copyright 2009-2021 Jörg Müller
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file RingBuffer.h
|
||||
* @ingroup util
|
||||
* The RingBuffer class.
|
||||
*/
|
||||
|
||||
#include "Audaspace.h"
|
||||
#include "Buffer.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
AUD_NAMESPACE_BEGIN
|
||||
|
||||
/**
|
||||
* This class is a simple ring buffer in RAM which is 32 Byte aligned and provides
|
||||
* functionality for concurrent reading and writting without locks.
|
||||
*/
|
||||
class AUD_API RingBuffer
|
||||
{
|
||||
private:
|
||||
/// The buffer storing the actual data.
|
||||
Buffer m_buffer;
|
||||
|
||||
/// The reading pointer.
|
||||
volatile size_t m_read;
|
||||
|
||||
/// The writing pointer.
|
||||
volatile size_t m_write;
|
||||
|
||||
// delete copy constructor and operator=
|
||||
RingBuffer(const RingBuffer&) = delete;
|
||||
RingBuffer& operator=(const RingBuffer&) = delete;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a new ring buffer.
|
||||
* \param size The size of the buffer in bytes.
|
||||
*/
|
||||
RingBuffer(int size = 0);
|
||||
|
||||
/**
|
||||
* Returns the pointer to the ring buffer in memory.
|
||||
*/
|
||||
sample_t* getBuffer() const;
|
||||
|
||||
/**
|
||||
* Returns the size of the ring buffer in bytes.
|
||||
*/
|
||||
int getSize() const;
|
||||
|
||||
size_t getReadSize() const;
|
||||
|
||||
size_t getWriteSize() const;
|
||||
|
||||
size_t read(data_t* target, size_t size);
|
||||
|
||||
size_t write(data_t* source, size_t size);
|
||||
|
||||
/**
|
||||
* Resets the ring buffer to a state where nothing has been written or read.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Resizes the ring buffer.
|
||||
* \param size The new size of the ring buffer, measured in bytes.
|
||||
*/
|
||||
void resize(int size);
|
||||
|
||||
/**
|
||||
* Makes sure the ring buffer has a minimum size.
|
||||
* If size is >= current size, nothing will happen.
|
||||
* Otherwise the ring buffer is resized with keep as parameter.
|
||||
* \param size The new minimum size of the ring buffer, measured in bytes.
|
||||
*/
|
||||
void assureSize(int size);
|
||||
};
|
||||
|
||||
AUD_NAMESPACE_END
|
18
extern/audaspace/plugins/ffmpeg/FFMPEG.cpp
vendored
18
extern/audaspace/plugins/ffmpeg/FFMPEG.cpp
vendored
@@ -35,14 +35,24 @@ void FFMPEG::registerPlugin()
|
||||
FileManager::registerOutput(plugin);
|
||||
}
|
||||
|
||||
std::shared_ptr<IReader> FFMPEG::createReader(std::string filename)
|
||||
std::shared_ptr<IReader> FFMPEG::createReader(std::string filename, int stream)
|
||||
{
|
||||
return std::shared_ptr<IReader>(new FFMPEGReader(filename));
|
||||
return std::shared_ptr<IReader>(new FFMPEGReader(filename, stream));
|
||||
}
|
||||
|
||||
std::shared_ptr<IReader> FFMPEG::createReader(std::shared_ptr<Buffer> buffer)
|
||||
std::shared_ptr<IReader> FFMPEG::createReader(std::shared_ptr<Buffer> buffer, int stream)
|
||||
{
|
||||
return std::shared_ptr<IReader>(new FFMPEGReader(buffer));
|
||||
return std::shared_ptr<IReader>(new FFMPEGReader(buffer, stream));
|
||||
}
|
||||
|
||||
std::vector<StreamInfo> FFMPEG::queryStreams(std::string filename)
|
||||
{
|
||||
return FFMPEGReader(filename).queryStreams();
|
||||
}
|
||||
|
||||
std::vector<StreamInfo> FFMPEG::queryStreams(std::shared_ptr<Buffer> buffer)
|
||||
{
|
||||
return FFMPEGReader(buffer).queryStreams();
|
||||
}
|
||||
|
||||
std::shared_ptr<IWriter> FFMPEG::createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate)
|
||||
|
6
extern/audaspace/plugins/ffmpeg/FFMPEG.h
vendored
6
extern/audaspace/plugins/ffmpeg/FFMPEG.h
vendored
@@ -52,8 +52,10 @@ public:
|
||||
*/
|
||||
static void registerPlugin();
|
||||
|
||||
virtual std::shared_ptr<IReader> createReader(std::string filename);
|
||||
virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer);
|
||||
virtual std::shared_ptr<IReader> createReader(std::string filename, int stream = 0);
|
||||
virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer, int stream = 0);
|
||||
virtual std::vector<StreamInfo> queryStreams(std::string filename);
|
||||
virtual std::vector<StreamInfo> queryStreams(std::shared_ptr<Buffer> buffer);
|
||||
virtual std::shared_ptr<IWriter> createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate);
|
||||
};
|
||||
|
||||
|
169
extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
vendored
169
extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
vendored
@@ -31,6 +31,25 @@ AUD_NAMESPACE_BEGIN
|
||||
#define FFMPEG_OLD_CODE
|
||||
#endif
|
||||
|
||||
SampleFormat FFMPEGReader::convertSampleFormat(AVSampleFormat format)
|
||||
{
|
||||
switch(av_get_packed_sample_fmt(format))
|
||||
{
|
||||
case AV_SAMPLE_FMT_U8:
|
||||
return FORMAT_U8;
|
||||
case AV_SAMPLE_FMT_S16:
|
||||
return FORMAT_S16;
|
||||
case AV_SAMPLE_FMT_S32:
|
||||
return FORMAT_S32;
|
||||
case AV_SAMPLE_FMT_FLT:
|
||||
return FORMAT_FLOAT32;
|
||||
case AV_SAMPLE_FMT_DBL:
|
||||
return FORMAT_FLOAT64;
|
||||
default:
|
||||
AUD_THROW(FileException, "FFMPEG sample format unknown.");
|
||||
}
|
||||
}
|
||||
|
||||
int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
|
||||
{
|
||||
int buf_size = buffer.getSize();
|
||||
@@ -68,7 +87,7 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
|
||||
for(int i = 0; i < m_frame->nb_samples; i++)
|
||||
{
|
||||
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
|
||||
m_frame->data[channel] + i * single_size, single_size);
|
||||
m_frame->data[channel] + i * single_size, single_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,7 +128,7 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
|
||||
for(int i = 0; i < m_frame->nb_samples; i++)
|
||||
{
|
||||
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
|
||||
m_frame->data[channel] + i * single_size, single_size);
|
||||
m_frame->data[channel] + i * single_size, single_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,13 +142,10 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
|
||||
return buf_pos;
|
||||
}
|
||||
|
||||
void FFMPEGReader::init()
|
||||
void FFMPEGReader::init(int stream)
|
||||
{
|
||||
m_position = 0;
|
||||
m_start_offset = 0.0f;
|
||||
m_pkgbuf_left = 0;
|
||||
m_st_time = 0;
|
||||
m_duration = 0;
|
||||
|
||||
if(avformat_find_stream_info(m_formatCtx, nullptr) < 0)
|
||||
AUD_THROW(FileException, "File couldn't be read, ffmpeg couldn't find the stream info.");
|
||||
@@ -137,43 +153,22 @@ void FFMPEGReader::init()
|
||||
// find audio stream and codec
|
||||
m_stream = -1;
|
||||
|
||||
double dur_sec = 0;
|
||||
|
||||
for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
|
||||
{
|
||||
#ifdef FFMPEG_OLD_CODE
|
||||
if(m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
if((m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
#else
|
||||
if(m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
if((m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
#endif
|
||||
&& (m_stream < 0))
|
||||
{
|
||||
AVStream *audio_stream = m_formatCtx->streams[i];
|
||||
double audio_timebase = av_q2d(audio_stream->time_base);
|
||||
|
||||
if (audio_stream->start_time != AV_NOPTS_VALUE)
|
||||
if(stream == 0)
|
||||
{
|
||||
m_st_time = audio_stream->start_time;
|
||||
}
|
||||
|
||||
int64_t ctx_start_time = 0;
|
||||
if (m_formatCtx->start_time != AV_NOPTS_VALUE) {
|
||||
ctx_start_time = m_formatCtx->start_time;
|
||||
}
|
||||
|
||||
m_start_offset = m_st_time * audio_timebase - (double)ctx_start_time / AV_TIME_BASE;
|
||||
|
||||
if(audio_stream->duration != AV_NOPTS_VALUE)
|
||||
{
|
||||
dur_sec = audio_stream->duration * audio_timebase;
|
||||
m_stream=i;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the audio starts after the stream start time, subract this from the total duration. */
|
||||
dur_sec = (double)m_formatCtx->duration / AV_TIME_BASE - m_start_offset;
|
||||
}
|
||||
|
||||
m_stream=i;
|
||||
break;
|
||||
stream--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,10 +237,9 @@ void FFMPEGReader::init()
|
||||
}
|
||||
|
||||
m_specs.rate = (SampleRate) m_codecCtx->sample_rate;
|
||||
m_duration = lround(dur_sec * m_codecCtx->sample_rate);
|
||||
}
|
||||
|
||||
FFMPEGReader::FFMPEGReader(std::string filename) :
|
||||
FFMPEGReader::FFMPEGReader(std::string filename, int stream) :
|
||||
m_pkgbuf(),
|
||||
m_formatCtx(nullptr),
|
||||
m_codecCtx(nullptr),
|
||||
@@ -259,7 +253,7 @@ FFMPEGReader::FFMPEGReader(std::string filename) :
|
||||
|
||||
try
|
||||
{
|
||||
init();
|
||||
init(stream);
|
||||
}
|
||||
catch(Exception&)
|
||||
{
|
||||
@@ -268,7 +262,7 @@ FFMPEGReader::FFMPEGReader(std::string filename) :
|
||||
}
|
||||
}
|
||||
|
||||
FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) :
|
||||
FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer, int stream) :
|
||||
m_pkgbuf(),
|
||||
m_codecCtx(nullptr),
|
||||
m_frame(nullptr),
|
||||
@@ -295,7 +289,7 @@ FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) :
|
||||
|
||||
try
|
||||
{
|
||||
init();
|
||||
init(stream);
|
||||
}
|
||||
catch(Exception&)
|
||||
{
|
||||
@@ -318,6 +312,51 @@ FFMPEGReader::~FFMPEGReader()
|
||||
avformat_close_input(&m_formatCtx);
|
||||
}
|
||||
|
||||
std::vector<StreamInfo> FFMPEGReader::queryStreams()
|
||||
{
|
||||
std::vector<StreamInfo> result;
|
||||
|
||||
for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
|
||||
{
|
||||
#ifdef FFMPEG_OLD_CODE
|
||||
if(m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
#else
|
||||
if(m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
#endif
|
||||
{
|
||||
StreamInfo info;
|
||||
|
||||
double time_base = av_q2d(m_formatCtx->streams[i]->time_base);
|
||||
|
||||
if(m_formatCtx->streams[i]->start_time != AV_NOPTS_VALUE)
|
||||
info.start = m_formatCtx->streams[i]->start_time * time_base;
|
||||
else
|
||||
info.start = 0;
|
||||
|
||||
if(m_formatCtx->streams[i]->duration != AV_NOPTS_VALUE)
|
||||
info.duration = m_formatCtx->streams[i]->duration * time_base;
|
||||
else if(m_formatCtx->duration != AV_NOPTS_VALUE)
|
||||
info.duration = double(m_formatCtx->duration) / AV_TIME_BASE - info.start;
|
||||
else
|
||||
info.duration = 0;
|
||||
|
||||
#ifdef FFMPEG_OLD_CODE
|
||||
info.specs.channels = Channels(m_formatCtx->streams[i]->codec->channels);
|
||||
info.specs.rate = m_formatCtx->streams[i]->codec->sample_rate;
|
||||
info.specs.format = convertSampleFormat(m_formatCtx->streams[i]->codec->sample_fmt);
|
||||
#else
|
||||
info.specs.channels = Channels(m_formatCtx->streams[i]->codecpar->channels);
|
||||
info.specs.rate = m_formatCtx->streams[i]->codecpar->sample_rate;
|
||||
info.specs.format = convertSampleFormat(AVSampleFormat(m_formatCtx->streams[i]->codecpar->format));
|
||||
#endif
|
||||
|
||||
result.emplace_back(info);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int FFMPEGReader::read_packet(void* opaque, uint8_t* buf, int buf_size)
|
||||
{
|
||||
FFMPEGReader* reader = reinterpret_cast<FFMPEGReader*>(opaque);
|
||||
@@ -368,18 +407,16 @@ void FFMPEGReader::seek(int position)
|
||||
{
|
||||
if(position >= 0)
|
||||
{
|
||||
double pts_time_base =
|
||||
av_q2d(m_formatCtx->streams[m_stream]->time_base);
|
||||
double pts_time_base = av_q2d(m_formatCtx->streams[m_stream]->time_base);
|
||||
|
||||
uint64_t seek_pts = (((uint64_t)position) / ((uint64_t)m_specs.rate)) / pts_time_base;
|
||||
uint64_t st_time = m_formatCtx->streams[m_stream]->start_time;
|
||||
uint64_t seek_pos = (uint64_t)(position / (pts_time_base * m_specs.rate));
|
||||
|
||||
if(m_st_time != AV_NOPTS_VALUE) {
|
||||
seek_pts += m_st_time;
|
||||
}
|
||||
if(st_time != AV_NOPTS_VALUE)
|
||||
seek_pos += st_time;
|
||||
|
||||
// a value < 0 tells us that seeking failed
|
||||
if(av_seek_frame(m_formatCtx, m_stream, seek_pts,
|
||||
AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0)
|
||||
if(av_seek_frame(m_formatCtx, m_stream, seek_pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0)
|
||||
{
|
||||
avcodec_flush_buffers(m_codecCtx);
|
||||
m_position = position;
|
||||
@@ -400,7 +437,7 @@ void FFMPEGReader::seek(int position)
|
||||
if(packet.pts != AV_NOPTS_VALUE)
|
||||
{
|
||||
// calculate real position, and read to frame!
|
||||
m_position = (packet.pts - m_st_time) * pts_time_base * m_specs.rate;
|
||||
m_position = (packet.pts - (st_time != AV_NOPTS_VALUE ? st_time : 0)) * pts_time_base * m_specs.rate;
|
||||
|
||||
if(m_position < position)
|
||||
{
|
||||
@@ -430,8 +467,25 @@ void FFMPEGReader::seek(int position)
|
||||
|
||||
int FFMPEGReader::getLength() const
|
||||
{
|
||||
auto stream = m_formatCtx->streams[m_stream];
|
||||
|
||||
double time_base = av_q2d(stream->time_base);
|
||||
double duration;
|
||||
|
||||
if(stream->duration != AV_NOPTS_VALUE)
|
||||
duration = stream->duration * time_base;
|
||||
else if(m_formatCtx->duration != AV_NOPTS_VALUE)
|
||||
{
|
||||
duration = float(m_formatCtx->duration) / AV_TIME_BASE;
|
||||
|
||||
if(stream->start_time != AV_NOPTS_VALUE)
|
||||
duration -= stream->start_time * time_base;
|
||||
}
|
||||
else
|
||||
duration = -1;
|
||||
|
||||
// return approximated remaning size
|
||||
return m_duration - m_position;
|
||||
return (int)(duration * m_codecCtx->sample_rate) - m_position;
|
||||
}
|
||||
|
||||
int FFMPEGReader::getPosition() const
|
||||
@@ -439,11 +493,6 @@ int FFMPEGReader::getPosition() const
|
||||
return m_position;
|
||||
}
|
||||
|
||||
double FFMPEGReader::getStartOffset() const
|
||||
{
|
||||
return m_start_offset;
|
||||
}
|
||||
|
||||
Specs FFMPEGReader::getSpecs() const
|
||||
{
|
||||
return m_specs.specs;
|
||||
@@ -480,13 +529,11 @@ void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
|
||||
// decode the package
|
||||
pkgbuf_pos = decode(packet, m_pkgbuf);
|
||||
|
||||
if (packet.pts >= m_st_time) {
|
||||
// copy to output buffer
|
||||
data_size = std::min(pkgbuf_pos, left * sample_size);
|
||||
m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
|
||||
buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
|
||||
left -= data_size / sample_size;
|
||||
}
|
||||
// copy to output buffer
|
||||
data_size = std::min(pkgbuf_pos, left * sample_size);
|
||||
m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
|
||||
buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
|
||||
left -= data_size / sample_size;
|
||||
}
|
||||
av_packet_unref(&packet);
|
||||
}
|
||||
|
42
extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
vendored
42
extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
vendored
@@ -29,9 +29,11 @@
|
||||
#include "respec/ConverterFunctions.h"
|
||||
#include "IReader.h"
|
||||
#include "util/Buffer.h"
|
||||
#include "file/FileInfo.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
struct AVCodecContext;
|
||||
extern "C" {
|
||||
@@ -54,22 +56,6 @@ private:
|
||||
*/
|
||||
int m_position;
|
||||
|
||||
/**
|
||||
* The start offset in seconds relative to the media container start time.
|
||||
* IE how much the sound should be delayed to be kept in sync with the rest of the containter streams.
|
||||
*/
|
||||
double m_start_offset;
|
||||
|
||||
/**
|
||||
* The start time pts of the stream. All packets before this timestamp shouldn't be played back (only decoded).
|
||||
*/
|
||||
int64_t m_st_time;
|
||||
|
||||
/**
|
||||
* The duration of the audio stream in samples.
|
||||
*/
|
||||
int64_t m_duration;
|
||||
|
||||
/**
|
||||
* The specification of the audio data.
|
||||
*/
|
||||
@@ -135,6 +121,13 @@ private:
|
||||
*/
|
||||
bool m_tointerleave;
|
||||
|
||||
/**
|
||||
* Converts an ffmpeg sample format to an audaspace one.
|
||||
* \param format The AVSampleFormat sample format.
|
||||
* \return The sample format as SampleFormat.
|
||||
*/
|
||||
AUD_LOCAL static SampleFormat convertSampleFormat(AVSampleFormat format);
|
||||
|
||||
/**
|
||||
* Decodes a packet into the given buffer.
|
||||
* \param packet The AVPacket to decode.
|
||||
@@ -145,8 +138,9 @@ private:
|
||||
|
||||
/**
|
||||
* Initializes the object.
|
||||
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
|
||||
*/
|
||||
AUD_LOCAL void init();
|
||||
AUD_LOCAL void init(int stream);
|
||||
|
||||
// delete copy constructor and operator=
|
||||
FFMPEGReader(const FFMPEGReader&) = delete;
|
||||
@@ -156,24 +150,33 @@ public:
|
||||
/**
|
||||
* Creates a new reader.
|
||||
* \param filename The path to the file to be read.
|
||||
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
|
||||
* \exception Exception Thrown if the file specified does not exist or
|
||||
* cannot be read with ffmpeg.
|
||||
*/
|
||||
FFMPEGReader(std::string filename);
|
||||
FFMPEGReader(std::string filename, int stream = 0);
|
||||
|
||||
/**
|
||||
* Creates a new reader.
|
||||
* \param buffer The buffer to read from.
|
||||
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
|
||||
* \exception Exception Thrown if the buffer specified cannot be read
|
||||
* with ffmpeg.
|
||||
*/
|
||||
FFMPEGReader(std::shared_ptr<Buffer> buffer);
|
||||
FFMPEGReader(std::shared_ptr<Buffer> buffer, int stream = 0);
|
||||
|
||||
/**
|
||||
* Destroys the reader and closes the file.
|
||||
*/
|
||||
virtual ~FFMPEGReader();
|
||||
|
||||
/**
|
||||
* Queries the streams of a sound file.
|
||||
* \return A vector with as many streams as there are in the file.
|
||||
* \exception Exception Thrown if the file specified cannot be read.
|
||||
*/
|
||||
virtual std::vector<StreamInfo> queryStreams();
|
||||
|
||||
/**
|
||||
* Reads data to a memory buffer.
|
||||
* This function is used for avio only.
|
||||
@@ -198,7 +201,6 @@ public:
|
||||
virtual void seek(int position);
|
||||
virtual int getLength() const;
|
||||
virtual int getPosition() const;
|
||||
virtual double getStartOffset() const;
|
||||
virtual Specs getSpecs() const;
|
||||
virtual void read(int& length, bool& eos, sample_t* buffer);
|
||||
};
|
||||
|
14
extern/audaspace/plugins/libsndfile/SndFile.cpp
vendored
14
extern/audaspace/plugins/libsndfile/SndFile.cpp
vendored
@@ -32,16 +32,26 @@ void SndFile::registerPlugin()
|
||||
FileManager::registerOutput(plugin);
|
||||
}
|
||||
|
||||
std::shared_ptr<IReader> SndFile::createReader(std::string filename)
|
||||
std::shared_ptr<IReader> SndFile::createReader(std::string filename, int stream)
|
||||
{
|
||||
return std::shared_ptr<IReader>(new SndFileReader(filename));
|
||||
}
|
||||
|
||||
std::shared_ptr<IReader> SndFile::createReader(std::shared_ptr<Buffer> buffer)
|
||||
std::shared_ptr<IReader> SndFile::createReader(std::shared_ptr<Buffer> buffer, int stream)
|
||||
{
|
||||
return std::shared_ptr<IReader>(new SndFileReader(buffer));
|
||||
}
|
||||
|
||||
std::vector<StreamInfo> SndFile::queryStreams(std::string filename)
|
||||
{
|
||||
return SndFileReader(filename).queryStreams();
|
||||
}
|
||||
|
||||
std::vector<StreamInfo> SndFile::queryStreams(std::shared_ptr<Buffer> buffer)
|
||||
{
|
||||
return SndFileReader(buffer).queryStreams();
|
||||
}
|
||||
|
||||
std::shared_ptr<IWriter> SndFile::createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate)
|
||||
{
|
||||
return std::shared_ptr<IWriter>(new SndFileWriter(filename, specs, format, codec, bitrate));
|
||||
|
@@ -52,8 +52,10 @@ public:
|
||||
*/
|
||||
static void registerPlugin();
|
||||
|
||||
virtual std::shared_ptr<IReader> createReader(std::string filename);
|
||||
virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer);
|
||||
virtual std::shared_ptr<IReader> createReader(std::string filename, int stream = 0);
|
||||
virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer, int stream = 0);
|
||||
virtual std::vector<StreamInfo> queryStreams(std::string filename);
|
||||
virtual std::vector<StreamInfo> queryStreams(std::shared_ptr<Buffer> buffer);
|
||||
virtual std::shared_ptr<IWriter> createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate);
|
||||
};
|
||||
|
||||
|
@@ -118,6 +118,21 @@ SndFileReader::~SndFileReader()
|
||||
sf_close(m_sndfile);
|
||||
}
|
||||
|
||||
std::vector<StreamInfo> SndFileReader::queryStreams()
|
||||
{
|
||||
std::vector<StreamInfo> result;
|
||||
|
||||
StreamInfo info;
|
||||
info.start = 0;
|
||||
info.duration = double(getLength()) / m_specs.rate;
|
||||
info.specs.specs = m_specs;
|
||||
info.specs.format = FORMAT_FLOAT32;
|
||||
|
||||
result.emplace_back(info);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SndFileReader::isSeekable() const
|
||||
{
|
||||
return m_seekable;
|
||||
|
@@ -28,9 +28,12 @@
|
||||
* The SndFileReader class.
|
||||
*/
|
||||
|
||||
#include "file/FileInfo.h"
|
||||
|
||||
#include <string>
|
||||
#include <sndfile.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
AUD_NAMESPACE_BEGIN
|
||||
|
||||
@@ -96,6 +99,7 @@ public:
|
||||
/**
|
||||
* Creates a new reader.
|
||||
* \param filename The path to the file to be read.
|
||||
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
|
||||
* \exception Exception Thrown if the file specified does not exist or
|
||||
* cannot be read with libsndfile.
|
||||
*/
|
||||
@@ -104,6 +108,7 @@ public:
|
||||
/**
|
||||
* Creates a new reader.
|
||||
* \param buffer The buffer to read from.
|
||||
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
|
||||
* \exception Exception Thrown if the buffer specified cannot be read
|
||||
* with libsndfile.
|
||||
*/
|
||||
@@ -114,6 +119,13 @@ public:
|
||||
*/
|
||||
virtual ~SndFileReader();
|
||||
|
||||
/**
|
||||
* Queries the streams of a sound file.
|
||||
* \return A vector with as many streams as there are in the file.
|
||||
* \exception Exception Thrown if the file specified cannot be read.
|
||||
*/
|
||||
virtual std::vector<StreamInfo> queryStreams();
|
||||
|
||||
virtual bool isSeekable() const;
|
||||
virtual void seek(int position);
|
||||
virtual int getLength() const;
|
||||
|
@@ -23,95 +23,121 @@
|
||||
|
||||
AUD_NAMESPACE_BEGIN
|
||||
|
||||
PulseAudioDevice::PulseAudioSynchronizer::PulseAudioSynchronizer(PulseAudioDevice *device) :
|
||||
m_device(device)
|
||||
{
|
||||
}
|
||||
|
||||
double PulseAudioDevice::PulseAudioSynchronizer::getPosition(std::shared_ptr<IHandle> handle)
|
||||
{
|
||||
pa_usec_t latency;
|
||||
int negative;
|
||||
AUD_pa_stream_get_latency(m_device->m_stream, &latency, &negative);
|
||||
|
||||
double delay = m_device->m_ring_buffer.getReadSize() / (AUD_SAMPLE_SIZE(m_device->m_specs) * m_device->m_specs.rate) + latency * 1.0e-6;
|
||||
|
||||
return handle->getPosition() - delay;
|
||||
}
|
||||
|
||||
void PulseAudioDevice::updateRingBuffer()
|
||||
{
|
||||
unsigned int samplesize = AUD_SAMPLE_SIZE(m_specs);
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mixingLock);
|
||||
|
||||
Buffer buffer;
|
||||
|
||||
while(m_valid)
|
||||
{
|
||||
size_t size = m_ring_buffer.getWriteSize();
|
||||
|
||||
size_t sample_count = size / samplesize;
|
||||
|
||||
if(sample_count > 0)
|
||||
{
|
||||
size = sample_count * samplesize;
|
||||
|
||||
buffer.assureSize(size);
|
||||
|
||||
mix(reinterpret_cast<data_t*>(buffer.getBuffer()), sample_count);
|
||||
|
||||
m_ring_buffer.write(reinterpret_cast<data_t*>(buffer.getBuffer()), size);
|
||||
}
|
||||
|
||||
m_mixingCondition.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
void PulseAudioDevice::PulseAudio_state_callback(pa_context *context, void *data)
|
||||
{
|
||||
PulseAudioDevice* device = (PulseAudioDevice*)data;
|
||||
|
||||
std::lock_guard<ILockable> lock(*device);
|
||||
|
||||
device->m_state = AUD_pa_context_get_state(context);
|
||||
|
||||
AUD_pa_threaded_mainloop_signal(device->m_mainloop, 0);
|
||||
}
|
||||
|
||||
void PulseAudioDevice::PulseAudio_request(pa_stream *stream, size_t total_bytes, void *data)
|
||||
{
|
||||
PulseAudioDevice* device = (PulseAudioDevice*)data;
|
||||
|
||||
void* buffer;
|
||||
data_t* buffer;
|
||||
|
||||
size_t sample_size = AUD_DEVICE_SAMPLE_SIZE(device->m_specs);
|
||||
|
||||
while(total_bytes > 0)
|
||||
{
|
||||
size_t num_bytes = total_bytes;
|
||||
|
||||
AUD_pa_stream_begin_write(stream, &buffer, &num_bytes);
|
||||
AUD_pa_stream_begin_write(stream, reinterpret_cast<void**>(&buffer), &num_bytes);
|
||||
|
||||
device->mix((data_t*)buffer, num_bytes / AUD_DEVICE_SAMPLE_SIZE(device->m_specs));
|
||||
size_t readsamples = device->m_ring_buffer.getReadSize();
|
||||
|
||||
AUD_pa_stream_write(stream, buffer, num_bytes, nullptr, 0, PA_SEEK_RELATIVE);
|
||||
readsamples = std::min(readsamples, size_t(num_bytes)) / sample_size;
|
||||
|
||||
device->m_ring_buffer.read(buffer, readsamples * sample_size);
|
||||
|
||||
if(readsamples * sample_size < num_bytes)
|
||||
std::memset(buffer + readsamples * sample_size, 0, num_bytes - readsamples * sample_size);
|
||||
|
||||
if(device->m_mixingLock.try_lock())
|
||||
{
|
||||
device->m_mixingCondition.notify_all();
|
||||
device->m_mixingLock.unlock();
|
||||
}
|
||||
|
||||
AUD_pa_stream_write(stream, reinterpret_cast<void*>(buffer), num_bytes, nullptr, 0, PA_SEEK_RELATIVE);
|
||||
|
||||
total_bytes -= num_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
void PulseAudioDevice::PulseAudio_underflow(pa_stream *stream, void *data)
|
||||
void PulseAudioDevice::playing(bool playing)
|
||||
{
|
||||
PulseAudioDevice* device = (PulseAudioDevice*)data;
|
||||
m_playback = playing;
|
||||
|
||||
DeviceSpecs specs = device->getSpecs();
|
||||
|
||||
if(++device->m_underflows > 4 && device->m_buffersize < AUD_DEVICE_SAMPLE_SIZE(specs) * specs.rate * 2)
|
||||
{
|
||||
device->m_buffersize <<= 1;
|
||||
device->m_underflows = 0;
|
||||
|
||||
pa_buffer_attr buffer_attr;
|
||||
|
||||
buffer_attr.fragsize = -1U;
|
||||
buffer_attr.maxlength = -1U;
|
||||
buffer_attr.minreq = -1U;
|
||||
buffer_attr.prebuf = -1U;
|
||||
buffer_attr.tlength = device->m_buffersize;
|
||||
|
||||
AUD_pa_stream_set_buffer_attr(stream, &buffer_attr, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void PulseAudioDevice::runMixingThread()
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
{
|
||||
std::lock_guard<ILockable> lock(*this);
|
||||
|
||||
if(shouldStop())
|
||||
{
|
||||
AUD_pa_stream_cork(m_stream, 1, nullptr, nullptr);
|
||||
AUD_pa_stream_flush(m_stream, nullptr, nullptr);
|
||||
doStop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(AUD_pa_stream_is_corked(m_stream))
|
||||
AUD_pa_stream_cork(m_stream, 0, nullptr, nullptr);
|
||||
|
||||
// similar to AUD_pa_mainloop_iterate(m_mainloop, false, nullptr); except with a longer timeout
|
||||
AUD_pa_mainloop_prepare(m_mainloop, 1 << 14);
|
||||
AUD_pa_mainloop_poll(m_mainloop);
|
||||
AUD_pa_mainloop_dispatch(m_mainloop);
|
||||
}
|
||||
AUD_pa_threaded_mainloop_lock(m_mainloop);
|
||||
AUD_pa_stream_cork(m_stream, playing ? 0 : 1, nullptr, nullptr);
|
||||
AUD_pa_threaded_mainloop_unlock(m_mainloop);
|
||||
}
|
||||
|
||||
PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buffersize) :
|
||||
m_synchronizer(this),
|
||||
m_playback(false),
|
||||
m_state(PA_CONTEXT_UNCONNECTED),
|
||||
m_valid(true),
|
||||
m_underflows(0)
|
||||
{
|
||||
m_mainloop = AUD_pa_mainloop_new();
|
||||
m_mainloop = AUD_pa_threaded_mainloop_new();
|
||||
|
||||
m_context = AUD_pa_context_new(AUD_pa_mainloop_get_api(m_mainloop), name.c_str());
|
||||
AUD_pa_threaded_mainloop_lock(m_mainloop);
|
||||
|
||||
m_context = AUD_pa_context_new(AUD_pa_threaded_mainloop_get_api(m_mainloop), name.c_str());
|
||||
|
||||
if(!m_context)
|
||||
{
|
||||
AUD_pa_mainloop_free(m_mainloop);
|
||||
AUD_pa_threaded_mainloop_unlock(m_mainloop);
|
||||
AUD_pa_threaded_mainloop_free(m_mainloop);
|
||||
|
||||
AUD_THROW(DeviceException, "Could not connect to PulseAudio.");
|
||||
}
|
||||
@@ -120,21 +146,26 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
|
||||
|
||||
AUD_pa_context_connect(m_context, nullptr, PA_CONTEXT_NOFLAGS, nullptr);
|
||||
|
||||
AUD_pa_threaded_mainloop_start(m_mainloop);
|
||||
|
||||
while(m_state != PA_CONTEXT_READY)
|
||||
{
|
||||
switch(m_state)
|
||||
{
|
||||
case PA_CONTEXT_FAILED:
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
AUD_pa_threaded_mainloop_unlock(m_mainloop);
|
||||
AUD_pa_threaded_mainloop_stop(m_mainloop);
|
||||
|
||||
AUD_pa_context_disconnect(m_context);
|
||||
AUD_pa_context_unref(m_context);
|
||||
|
||||
AUD_pa_mainloop_free(m_mainloop);
|
||||
AUD_pa_threaded_mainloop_free(m_mainloop);
|
||||
|
||||
AUD_THROW(DeviceException, "Could not connect to PulseAudio.");
|
||||
break;
|
||||
default:
|
||||
AUD_pa_mainloop_iterate(m_mainloop, true, nullptr);
|
||||
AUD_pa_threaded_mainloop_wait(m_mainloop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -182,16 +213,18 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
|
||||
|
||||
if(!m_stream)
|
||||
{
|
||||
AUD_pa_threaded_mainloop_unlock(m_mainloop);
|
||||
AUD_pa_threaded_mainloop_stop(m_mainloop);
|
||||
|
||||
AUD_pa_context_disconnect(m_context);
|
||||
AUD_pa_context_unref(m_context);
|
||||
|
||||
AUD_pa_mainloop_free(m_mainloop);
|
||||
AUD_pa_threaded_mainloop_free(m_mainloop);
|
||||
|
||||
AUD_THROW(DeviceException, "Could not create PulseAudio stream.");
|
||||
}
|
||||
|
||||
AUD_pa_stream_set_write_callback(m_stream, PulseAudio_request, this);
|
||||
AUD_pa_stream_set_underflow_callback(m_stream, PulseAudio_underflow, this);
|
||||
|
||||
buffersize *= AUD_DEVICE_SAMPLE_SIZE(m_specs);
|
||||
m_buffersize = buffersize;
|
||||
@@ -204,31 +237,53 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
|
||||
buffer_attr.prebuf = -1U;
|
||||
buffer_attr.tlength = buffersize;
|
||||
|
||||
if(AUD_pa_stream_connect_playback(m_stream, nullptr, &buffer_attr, static_cast<pa_stream_flags_t>(PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr) < 0)
|
||||
m_ring_buffer.resize(buffersize);
|
||||
|
||||
if(AUD_pa_stream_connect_playback(m_stream, nullptr, &buffer_attr, static_cast<pa_stream_flags_t>(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr) < 0)
|
||||
{
|
||||
AUD_pa_threaded_mainloop_unlock(m_mainloop);
|
||||
AUD_pa_threaded_mainloop_stop(m_mainloop);
|
||||
|
||||
AUD_pa_context_disconnect(m_context);
|
||||
AUD_pa_context_unref(m_context);
|
||||
|
||||
AUD_pa_mainloop_free(m_mainloop);
|
||||
AUD_pa_threaded_mainloop_free(m_mainloop);
|
||||
|
||||
AUD_THROW(DeviceException, "Could not connect PulseAudio stream.");
|
||||
}
|
||||
|
||||
AUD_pa_threaded_mainloop_unlock(m_mainloop);
|
||||
|
||||
create();
|
||||
|
||||
m_mixingThread = std::thread(&PulseAudioDevice::updateRingBuffer, this);
|
||||
}
|
||||
|
||||
PulseAudioDevice::~PulseAudioDevice()
|
||||
{
|
||||
stopMixingThread();
|
||||
m_valid = false;
|
||||
|
||||
m_mixingLock.lock();
|
||||
m_mixingCondition.notify_all();
|
||||
m_mixingLock.unlock();
|
||||
|
||||
m_mixingThread.join();
|
||||
|
||||
AUD_pa_threaded_mainloop_stop(m_mainloop);
|
||||
|
||||
AUD_pa_context_disconnect(m_context);
|
||||
AUD_pa_context_unref(m_context);
|
||||
|
||||
AUD_pa_mainloop_free(m_mainloop);
|
||||
AUD_pa_threaded_mainloop_free(m_mainloop);
|
||||
|
||||
destroy();
|
||||
}
|
||||
|
||||
ISynchronizer *PulseAudioDevice::getSynchronizer()
|
||||
{
|
||||
return &m_synchronizer;
|
||||
}
|
||||
|
||||
class PulseAudioDeviceFactory : public IDeviceFactory
|
||||
{
|
||||
private:
|
||||
|
@@ -26,7 +26,11 @@
|
||||
* The PulseAudioDevice class.
|
||||
*/
|
||||
|
||||
#include "devices/ThreadedDevice.h"
|
||||
#include "devices/SoftwareDevice.h"
|
||||
#include "util/RingBuffer.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
|
||||
#include <pulse/pulseaudio.h>
|
||||
|
||||
@@ -35,17 +39,65 @@ AUD_NAMESPACE_BEGIN
|
||||
/**
|
||||
* This device plays back through PulseAudio, the simple direct media layer.
|
||||
*/
|
||||
class AUD_PLUGIN_API PulseAudioDevice : public ThreadedDevice
|
||||
class AUD_PLUGIN_API PulseAudioDevice : public SoftwareDevice
|
||||
{
|
||||
private:
|
||||
pa_mainloop* m_mainloop;
|
||||
class PulseAudioSynchronizer : public DefaultSynchronizer
|
||||
{
|
||||
PulseAudioDevice* m_device;
|
||||
|
||||
public:
|
||||
PulseAudioSynchronizer(PulseAudioDevice* device);
|
||||
|
||||
virtual double getPosition(std::shared_ptr<IHandle> handle);
|
||||
};
|
||||
|
||||
/// Synchronizer.
|
||||
PulseAudioSynchronizer m_synchronizer;
|
||||
|
||||
/**
|
||||
* Whether there is currently playback.
|
||||
*/
|
||||
volatile bool m_playback;
|
||||
|
||||
pa_threaded_mainloop* m_mainloop;
|
||||
pa_context* m_context;
|
||||
pa_stream* m_stream;
|
||||
pa_context_state_t m_state;
|
||||
|
||||
/**
|
||||
* The mixing ring buffer.
|
||||
*/
|
||||
RingBuffer m_ring_buffer;
|
||||
|
||||
/**
|
||||
* Whether the device is valid.
|
||||
*/
|
||||
bool m_valid;
|
||||
|
||||
int m_buffersize;
|
||||
uint32_t m_underflows;
|
||||
|
||||
/**
|
||||
* The mixing thread.
|
||||
*/
|
||||
std::thread m_mixingThread;
|
||||
|
||||
/**
|
||||
* Mutex for mixing.
|
||||
*/
|
||||
std::mutex m_mixingLock;
|
||||
|
||||
/**
|
||||
* Condition for mixing.
|
||||
*/
|
||||
std::condition_variable m_mixingCondition;
|
||||
|
||||
/**
|
||||
* Updates the ring buffer.
|
||||
*/
|
||||
AUD_LOCAL void updateRingBuffer();
|
||||
|
||||
/**
|
||||
* Reports the state of the PulseAudio server connection.
|
||||
* \param context The PulseAudio context.
|
||||
@@ -61,23 +113,13 @@ private:
|
||||
*/
|
||||
AUD_LOCAL static void PulseAudio_request(pa_stream* stream, size_t total_bytes, void* data);
|
||||
|
||||
/**
|
||||
* Reports an underflow from the PulseAudio server.
|
||||
* Automatically adjusts the latency if this happens too often.
|
||||
* @param stream The PulseAudio stream.
|
||||
* \param data The PulseAudio device.
|
||||
*/
|
||||
AUD_LOCAL static void PulseAudio_underflow(pa_stream* stream, void* data);
|
||||
|
||||
/**
|
||||
* Streaming thread main function.
|
||||
*/
|
||||
AUD_LOCAL void runMixingThread();
|
||||
|
||||
// delete copy constructor and operator=
|
||||
PulseAudioDevice(const PulseAudioDevice&) = delete;
|
||||
PulseAudioDevice& operator=(const PulseAudioDevice&) = delete;
|
||||
|
||||
protected:
|
||||
virtual void playing(bool playing);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Opens the PulseAudio audio device for playback.
|
||||
@@ -93,6 +135,8 @@ public:
|
||||
*/
|
||||
virtual ~PulseAudioDevice();
|
||||
|
||||
virtual ISynchronizer* getSynchronizer();
|
||||
|
||||
/**
|
||||
* Registers this plugin.
|
||||
*/
|
||||
|
@@ -25,6 +25,7 @@ PULSEAUDIO_SYMBOL(pa_stream_begin_write);
|
||||
PULSEAUDIO_SYMBOL(pa_stream_connect_playback);
|
||||
PULSEAUDIO_SYMBOL(pa_stream_cork);
|
||||
PULSEAUDIO_SYMBOL(pa_stream_flush);
|
||||
PULSEAUDIO_SYMBOL(pa_stream_get_latency);
|
||||
PULSEAUDIO_SYMBOL(pa_stream_is_corked);
|
||||
PULSEAUDIO_SYMBOL(pa_stream_new);
|
||||
PULSEAUDIO_SYMBOL(pa_stream_set_buffer_attr);
|
||||
@@ -39,3 +40,13 @@ PULSEAUDIO_SYMBOL(pa_mainloop_iterate);
|
||||
PULSEAUDIO_SYMBOL(pa_mainloop_prepare);
|
||||
PULSEAUDIO_SYMBOL(pa_mainloop_poll);
|
||||
PULSEAUDIO_SYMBOL(pa_mainloop_dispatch);
|
||||
|
||||
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_free);
|
||||
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_get_api);
|
||||
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_lock);
|
||||
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_new);
|
||||
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_signal);
|
||||
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_start);
|
||||
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_stop);
|
||||
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_unlock);
|
||||
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_wait);
|
||||
|
20
extern/audaspace/src/file/File.cpp
vendored
20
extern/audaspace/src/file/File.cpp
vendored
@@ -23,23 +23,31 @@
|
||||
|
||||
AUD_NAMESPACE_BEGIN
|
||||
|
||||
File::File(std::string filename) :
|
||||
m_filename(filename)
|
||||
File::File(std::string filename, int stream) :
|
||||
m_filename(filename), m_stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
File::File(const data_t* buffer, int size) :
|
||||
m_buffer(new Buffer(size))
|
||||
File::File(const data_t* buffer, int size, int stream) :
|
||||
m_buffer(new Buffer(size)), m_stream(stream)
|
||||
{
|
||||
std::memcpy(m_buffer->getBuffer(), buffer, size);
|
||||
}
|
||||
|
||||
std::vector<StreamInfo> File::queryStreams()
|
||||
{
|
||||
if(m_buffer.get())
|
||||
return FileManager::queryStreams(m_buffer);
|
||||
else
|
||||
return FileManager::queryStreams(m_filename);
|
||||
}
|
||||
|
||||
std::shared_ptr<IReader> File::createReader()
|
||||
{
|
||||
if(m_buffer.get())
|
||||
return FileManager::createReader(m_buffer);
|
||||
return FileManager::createReader(m_buffer, m_stream);
|
||||
else
|
||||
return FileManager::createReader(m_filename);
|
||||
return FileManager::createReader(m_filename, m_stream);
|
||||
}
|
||||
|
||||
AUD_NAMESPACE_END
|
||||
|
36
extern/audaspace/src/file/FileManager.cpp
vendored
36
extern/audaspace/src/file/FileManager.cpp
vendored
@@ -43,13 +43,13 @@ void FileManager::registerOutput(std::shared_ptr<aud::IFileOutput> output)
|
||||
outputs().push_back(output);
|
||||
}
|
||||
|
||||
std::shared_ptr<IReader> FileManager::createReader(std::string filename)
|
||||
std::shared_ptr<IReader> FileManager::createReader(std::string filename, int stream)
|
||||
{
|
||||
for(std::shared_ptr<IFileInput> input : inputs())
|
||||
{
|
||||
try
|
||||
{
|
||||
return input->createReader(filename);
|
||||
return input->createReader(filename, stream);
|
||||
}
|
||||
catch(Exception&) {}
|
||||
}
|
||||
@@ -57,13 +57,41 @@ std::shared_ptr<IReader> FileManager::createReader(std::string filename)
|
||||
AUD_THROW(FileException, "The file couldn't be read with any installed file reader.");
|
||||
}
|
||||
|
||||
std::shared_ptr<IReader> FileManager::createReader(std::shared_ptr<Buffer> buffer)
|
||||
std::shared_ptr<IReader> FileManager::createReader(std::shared_ptr<Buffer> buffer, int stream)
|
||||
{
|
||||
for(std::shared_ptr<IFileInput> input : inputs())
|
||||
{
|
||||
try
|
||||
{
|
||||
return input->createReader(buffer);
|
||||
return input->createReader(buffer, stream);
|
||||
}
|
||||
catch(Exception&) {}
|
||||
}
|
||||
|
||||
AUD_THROW(FileException, "The file couldn't be read with any installed file reader.");
|
||||
}
|
||||
|
||||
std::vector<StreamInfo> FileManager::queryStreams(std::string filename)
|
||||
{
|
||||
for(std::shared_ptr<IFileInput> input : inputs())
|
||||
{
|
||||
try
|
||||
{
|
||||
return input->queryStreams(filename);
|
||||
}
|
||||
catch(Exception&) {}
|
||||
}
|
||||
|
||||
AUD_THROW(FileException, "The file couldn't be read with any installed file reader.");
|
||||
}
|
||||
|
||||
std::vector<StreamInfo> FileManager::queryStreams(std::shared_ptr<Buffer> buffer)
|
||||
{
|
||||
for(std::shared_ptr<IFileInput> input : inputs())
|
||||
{
|
||||
try
|
||||
{
|
||||
return input->queryStreams(buffer);
|
||||
}
|
||||
catch(Exception&) {}
|
||||
}
|
||||
|
2
extern/audaspace/src/fx/VolumeReader.cpp
vendored
2
extern/audaspace/src/fx/VolumeReader.cpp
vendored
@@ -57,4 +57,4 @@ void VolumeReader::read(int& length, bool& eos, sample_t* buffer)
|
||||
buffer[i] = buffer[i] * m_volumeStorage->getVolume();
|
||||
}
|
||||
|
||||
AUD_NAMESPACE_END
|
||||
AUD_NAMESPACE_END
|
137
extern/audaspace/src/util/RingBuffer.cpp
vendored
Normal file
137
extern/audaspace/src/util/RingBuffer.cpp
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
/*******************************************************************************
|
||||
* Copyright 2009-2021 Jörg Müller
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
|
||||
#include "util/RingBuffer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
#define ALIGNMENT 32
|
||||
#define ALIGN(a) (a + ALIGNMENT - ((long long)a & (ALIGNMENT-1)))
|
||||
|
||||
AUD_NAMESPACE_BEGIN
|
||||
|
||||
RingBuffer::RingBuffer(int size) :
|
||||
m_buffer(size),
|
||||
m_read(0),
|
||||
m_write(0)
|
||||
{
|
||||
}
|
||||
|
||||
sample_t* RingBuffer::getBuffer() const
|
||||
{
|
||||
return m_buffer.getBuffer();
|
||||
}
|
||||
|
||||
int RingBuffer::getSize() const
|
||||
{
|
||||
return m_buffer.getSize();
|
||||
}
|
||||
|
||||
size_t RingBuffer::getReadSize() const
|
||||
{
|
||||
size_t read = m_read;
|
||||
size_t write = m_write;
|
||||
|
||||
if(read > write)
|
||||
return write + getSize() - read;
|
||||
else
|
||||
return write - read;
|
||||
}
|
||||
|
||||
size_t RingBuffer::getWriteSize() const
|
||||
{
|
||||
size_t read = m_read;
|
||||
size_t write = m_write;
|
||||
|
||||
if(read > write)
|
||||
return read - write - 1;
|
||||
else
|
||||
return read + getSize() - write - 1;
|
||||
}
|
||||
|
||||
size_t RingBuffer::read(data_t* target, size_t size)
|
||||
{
|
||||
size = std::min(size, getReadSize());
|
||||
|
||||
data_t* buffer = reinterpret_cast<data_t*>(m_buffer.getBuffer());
|
||||
|
||||
if(m_read + size > m_buffer.getSize())
|
||||
{
|
||||
size_t read_first = m_buffer.getSize() - m_read;
|
||||
size_t read_second = size - read_first;
|
||||
|
||||
std::memcpy(target, buffer + m_read, read_first);
|
||||
std::memcpy(target + read_first, buffer, read_second);
|
||||
|
||||
m_read = read_second;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::memcpy(target, buffer + m_read, size);
|
||||
|
||||
m_read += size;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t RingBuffer::write(data_t* source, size_t size)
|
||||
{
|
||||
size = std::min(size, getWriteSize());
|
||||
|
||||
data_t* buffer = reinterpret_cast<data_t*>(m_buffer.getBuffer());
|
||||
|
||||
if(m_write + size > m_buffer.getSize())
|
||||
{
|
||||
size_t write_first = m_buffer.getSize() - m_write;
|
||||
size_t write_second = size - write_first;
|
||||
|
||||
std::memcpy(buffer + m_write, source, write_first);
|
||||
std::memcpy(buffer, source + write_first, write_second);
|
||||
|
||||
m_write = write_second;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::memcpy(buffer + m_write, source, size);
|
||||
|
||||
m_write += size;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void RingBuffer::reset()
|
||||
{
|
||||
m_read = 0;
|
||||
m_write = 0;
|
||||
}
|
||||
|
||||
void RingBuffer::resize(int size)
|
||||
{
|
||||
m_buffer.resize(size);
|
||||
reset();
|
||||
}
|
||||
|
||||
void RingBuffer::assureSize(int size)
|
||||
{
|
||||
m_buffer.assureSize(size);
|
||||
reset();
|
||||
}
|
||||
|
||||
AUD_NAMESPACE_END
|
3
extern/cuew/include/cuew.h
vendored
3
extern/cuew/include/cuew.h
vendored
@@ -645,7 +645,8 @@ typedef enum CUdevice_P2PAttribute_enum {
|
||||
CU_DEVICE_P2P_ATTRIBUTE_PERFORMANCE_RANK = 0x01,
|
||||
CU_DEVICE_P2P_ATTRIBUTE_ACCESS_SUPPORTED = 0x02,
|
||||
CU_DEVICE_P2P_ATTRIBUTE_NATIVE_ATOMIC_SUPPORTED = 0x03,
|
||||
CU_DEVICE_P2P_ATTRIBUTE_ARRAY_ACCESS_ACCESS_SUPPORTED = 0x04,
|
||||
CU_DEVICE_P2P_ATTRIBUTE_ACCESS_ACCESS_SUPPORTED = 0x04,
|
||||
CU_DEVICE_P2P_ATTRIBUTE_CUDA_ARRAY_ACCESS_SUPPORTED = 0x04,
|
||||
} CUdevice_P2PAttribute;
|
||||
|
||||
typedef void (CUDA_CB *CUstreamCallback)(CUstream hStream, CUresult status, void* userData);
|
||||
|
5
extern/json/README.blender
vendored
Normal file
5
extern/json/README.blender
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
Project: JSON
|
||||
URL: https://github.com/nlohmann/json/
|
||||
License: MIT License
|
||||
Upstream version: 3.10.2
|
||||
Local modifications: None
|
26640
extern/json/include/json.hpp
vendored
Normal file
26640
extern/json/include/json.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
extern/mantaflow/UPDATE.sh
vendored
2
extern/mantaflow/UPDATE.sh
vendored
@@ -8,7 +8,7 @@
|
||||
|
||||
# YOUR INSTALLATION PATHS GO HERE:
|
||||
MANTA_INSTALLATION=/Users/sebbas/Developer/Mantaflow/mantaflowDevelop
|
||||
BLENDER_INSTALLATION=/Users/sebbas/Developer/Blender/fluid-mantaflow
|
||||
BLENDER_INSTALLATION=/Users/sebbas/Developer/Blender
|
||||
|
||||
# Try to check out Mantaflow repository before building?
|
||||
CLEAN_REPOSITORY=0
|
||||
|
@@ -28,11 +28,13 @@ extern PyTypeObject PbVec3Type;
|
||||
extern PyTypeObject PbVec4Type;
|
||||
|
||||
struct PbVec3 {
|
||||
PyObject_HEAD float data[3];
|
||||
PyObject_HEAD
|
||||
float data[3];
|
||||
};
|
||||
|
||||
struct PbVec4 {
|
||||
PyObject_HEAD float data[4];
|
||||
PyObject_HEAD
|
||||
float data[4];
|
||||
};
|
||||
|
||||
PyObject *getPyNone()
|
||||
|
6
extern/mantaflow/helper/pwrapper/pvec3.cpp
vendored
6
extern/mantaflow/helper/pwrapper/pvec3.cpp
vendored
@@ -25,7 +25,8 @@ namespace Manta {
|
||||
extern PyTypeObject PbVec3Type;
|
||||
|
||||
struct PbVec3 {
|
||||
PyObject_HEAD float data[3];
|
||||
PyObject_HEAD
|
||||
float data[3];
|
||||
};
|
||||
|
||||
static void PbVec3Dealloc(PbVec3 *self)
|
||||
@@ -293,7 +294,8 @@ inline PyObject *castPy(PyTypeObject *p)
|
||||
extern PyTypeObject PbVec4Type;
|
||||
|
||||
struct PbVec4 {
|
||||
PyObject_HEAD float data[4];
|
||||
PyObject_HEAD
|
||||
float data[4];
|
||||
};
|
||||
|
||||
static PyMethodDef PbVec4Methods[] = {
|
||||
|
@@ -76,7 +76,8 @@ struct ClassData {
|
||||
};
|
||||
|
||||
struct PbObject {
|
||||
PyObject_HEAD Manta::PbClass *instance;
|
||||
PyObject_HEAD
|
||||
Manta::PbClass *instance;
|
||||
ClassData *classdef;
|
||||
};
|
||||
|
||||
|
202
extern/mantaflow/preprocessed/fastmarch.cpp
vendored
202
extern/mantaflow/preprocessed/fastmarch.cpp
vendored
@@ -874,6 +874,136 @@ static const Vec3i nb[6] = {Vec3i(1, 0, 0),
|
||||
Vec3i(0, 0, 1),
|
||||
Vec3i(0, 0, -1)};
|
||||
|
||||
struct knMarkSkipCells : public KernelBase {
|
||||
knMarkSkipCells(Grid<Real> &phi, Grid<int> &tmp, bool inside)
|
||||
: KernelBase(&phi, 1), phi(phi), tmp(tmp), inside(inside)
|
||||
{
|
||||
runMessage();
|
||||
run();
|
||||
}
|
||||
inline void op(int i, int j, int k, Grid<Real> &phi, Grid<int> &tmp, bool inside) const
|
||||
{
|
||||
if (!inside && phi(i, j, k) < 0.) {
|
||||
tmp(i, j, k) = 1;
|
||||
}
|
||||
if (inside && phi(i, j, k) > 0.) {
|
||||
tmp(i, j, k) = 1;
|
||||
}
|
||||
}
|
||||
inline Grid<Real> &getArg0()
|
||||
{
|
||||
return phi;
|
||||
}
|
||||
typedef Grid<Real> type0;
|
||||
inline Grid<int> &getArg1()
|
||||
{
|
||||
return tmp;
|
||||
}
|
||||
typedef Grid<int> type1;
|
||||
inline bool &getArg2()
|
||||
{
|
||||
return inside;
|
||||
}
|
||||
typedef bool type2;
|
||||
void runMessage()
|
||||
{
|
||||
debMsg("Executing kernel knMarkSkipCells ", 3);
|
||||
debMsg("Kernel range"
|
||||
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
|
||||
4);
|
||||
};
|
||||
void operator()(const tbb::blocked_range<IndexInt> &__r) const
|
||||
{
|
||||
const int _maxX = maxX;
|
||||
const int _maxY = maxY;
|
||||
if (maxZ > 1) {
|
||||
for (int k = __r.begin(); k != (int)__r.end(); k++)
|
||||
for (int j = 1; j < _maxY; j++)
|
||||
for (int i = 1; i < _maxX; i++)
|
||||
op(i, j, k, phi, tmp, inside);
|
||||
}
|
||||
else {
|
||||
const int k = 0;
|
||||
for (int j = __r.begin(); j != (int)__r.end(); j++)
|
||||
for (int i = 1; i < _maxX; i++)
|
||||
op(i, j, k, phi, tmp, inside);
|
||||
}
|
||||
}
|
||||
void run()
|
||||
{
|
||||
if (maxZ > 1)
|
||||
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
|
||||
else
|
||||
tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
|
||||
}
|
||||
Grid<Real> φ
|
||||
Grid<int> &tmp;
|
||||
bool inside;
|
||||
};
|
||||
|
||||
struct knSetFirstLayer : public KernelBase {
|
||||
knSetFirstLayer(Grid<int> &tmp, int dim) : KernelBase(&tmp, 1), tmp(tmp), dim(dim)
|
||||
{
|
||||
runMessage();
|
||||
run();
|
||||
}
|
||||
inline void op(int i, int j, int k, Grid<int> &tmp, int dim) const
|
||||
{
|
||||
Vec3i p(i, j, k);
|
||||
if (tmp(p))
|
||||
return;
|
||||
for (int n = 0; n < 2 * dim; ++n) {
|
||||
if (tmp(p + nb[n]) == 1) {
|
||||
tmp(i, j, k) = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
inline Grid<int> &getArg0()
|
||||
{
|
||||
return tmp;
|
||||
}
|
||||
typedef Grid<int> type0;
|
||||
inline int &getArg1()
|
||||
{
|
||||
return dim;
|
||||
}
|
||||
typedef int type1;
|
||||
void runMessage()
|
||||
{
|
||||
debMsg("Executing kernel knSetFirstLayer ", 3);
|
||||
debMsg("Kernel range"
|
||||
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
|
||||
4);
|
||||
};
|
||||
void operator()(const tbb::blocked_range<IndexInt> &__r) const
|
||||
{
|
||||
const int _maxX = maxX;
|
||||
const int _maxY = maxY;
|
||||
if (maxZ > 1) {
|
||||
for (int k = __r.begin(); k != (int)__r.end(); k++)
|
||||
for (int j = 1; j < _maxY; j++)
|
||||
for (int i = 1; i < _maxX; i++)
|
||||
op(i, j, k, tmp, dim);
|
||||
}
|
||||
else {
|
||||
const int k = 0;
|
||||
for (int j = __r.begin(); j != (int)__r.end(); j++)
|
||||
for (int i = 1; i < _maxX; i++)
|
||||
op(i, j, k, tmp, dim);
|
||||
}
|
||||
}
|
||||
void run()
|
||||
{
|
||||
if (maxZ > 1)
|
||||
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
|
||||
else
|
||||
tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
|
||||
}
|
||||
Grid<int> &tmp;
|
||||
int dim;
|
||||
};
|
||||
|
||||
template<class S> struct knExtrapolateLsSimple : public KernelBase {
|
||||
knExtrapolateLsSimple(Grid<S> &val, int distance, Grid<int> &tmp, const int d, S direction)
|
||||
: KernelBase(&val, 1), val(val), distance(distance), tmp(tmp), d(d), direction(direction)
|
||||
@@ -1043,39 +1173,12 @@ void extrapolateLsSimple(Grid<Real> &phi, int distance = 4, bool inside = false)
|
||||
tmp.clear();
|
||||
const int dim = (phi.is3D() ? 3 : 2);
|
||||
|
||||
// by default, march outside
|
||||
Real direction = 1.;
|
||||
if (!inside) {
|
||||
// mark all inside
|
||||
FOR_IJK_BND(phi, 1)
|
||||
{
|
||||
if (phi(i, j, k) < 0.) {
|
||||
tmp(i, j, k) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
direction = -1.;
|
||||
FOR_IJK_BND(phi, 1)
|
||||
{
|
||||
if (phi(i, j, k) > 0.) {
|
||||
tmp(i, j, k) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// by default, march outside (ie mark all inside to be skipped)
|
||||
Real direction = (inside) ? -1. : 1.;
|
||||
knMarkSkipCells(phi, tmp, inside);
|
||||
|
||||
// + first layer around
|
||||
FOR_IJK_BND(phi, 1)
|
||||
{
|
||||
Vec3i p(i, j, k);
|
||||
if (tmp(p))
|
||||
continue;
|
||||
for (int n = 0; n < 2 * dim; ++n) {
|
||||
if (tmp(p + nb[n]) == 1) {
|
||||
tmp(i, j, k) = 2;
|
||||
n = 2 * dim;
|
||||
}
|
||||
}
|
||||
}
|
||||
knSetFirstLayer(tmp, dim);
|
||||
|
||||
// extrapolate for distance
|
||||
for (int d = 2; d < 1 + distance; ++d) {
|
||||
@@ -1126,37 +1229,12 @@ void extrapolateVec3Simple(Grid<Vec3> &vel, Grid<Real> &phi, int distance = 4, b
|
||||
tmp.clear();
|
||||
const int dim = (vel.is3D() ? 3 : 2);
|
||||
|
||||
// mark initial cells, by default, march outside
|
||||
if (!inside) {
|
||||
// mark all inside
|
||||
FOR_IJK_BND(phi, 1)
|
||||
{
|
||||
if (phi(i, j, k) < 0.) {
|
||||
tmp(i, j, k) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
FOR_IJK_BND(phi, 1)
|
||||
{
|
||||
if (phi(i, j, k) > 0.) {
|
||||
tmp(i, j, k) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// mark initial cells, by default, march outside (ie mark all inside to be skipped)
|
||||
Real direction = (inside) ? -1. : 1.;
|
||||
knMarkSkipCells(phi, tmp, inside);
|
||||
|
||||
// + first layer next to initial cells
|
||||
FOR_IJK_BND(vel, 1)
|
||||
{
|
||||
Vec3i p(i, j, k);
|
||||
if (tmp(p))
|
||||
continue;
|
||||
for (int n = 0; n < 2 * dim; ++n) {
|
||||
if (tmp(p + nb[n]) == 1) {
|
||||
tmp(i, j, k) = 2;
|
||||
n = 2 * dim;
|
||||
}
|
||||
}
|
||||
}
|
||||
knSetFirstLayer(tmp, dim);
|
||||
|
||||
for (int d = 2; d < 1 + distance; ++d) {
|
||||
knExtrapolateLsSimple<Vec3>(vel, distance, tmp, d, Vec3(0.));
|
||||
|
2
extern/mantaflow/preprocessed/gitinfo.h
vendored
2
extern/mantaflow/preprocessed/gitinfo.h
vendored
@@ -1,3 +1,3 @@
|
||||
|
||||
|
||||
#define MANTA_GIT_VERSION "commit 8fbebe02459b7f72575872c20961f7cb757db408"
|
||||
#define MANTA_GIT_VERSION "commit d5d9a6c28daa8f21426d7a285f48639c0d8fd13f"
|
||||
|
5
extern/tinygltf/README.blender
vendored
Normal file
5
extern/tinygltf/README.blender
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
Project: TinyGLTF
|
||||
URL: https://github.com/syoyo/tinygltf
|
||||
License: MIT
|
||||
Upstream version: 2.5.0, 19a41d20ec0
|
||||
Local modifications: None
|
7760
extern/tinygltf/tiny_gltf.h
vendored
Normal file
7760
extern/tinygltf/tiny_gltf.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -247,7 +247,7 @@ if(WITH_CYCLES_OSL)
|
||||
endif()
|
||||
|
||||
if(WITH_CYCLES_DEVICE_OPTIX)
|
||||
find_package(OptiX)
|
||||
find_package(OptiX 7.3.0)
|
||||
|
||||
if(OPTIX_FOUND)
|
||||
add_definitions(-DWITH_OPTIX)
|
||||
@@ -286,11 +286,17 @@ if(WITH_OPENSUBDIV)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENIMAGEDENOISE)
|
||||
add_definitions(-DWITH_OPENIMAGEDENOISE)
|
||||
add_definitions(-DOIDN_STATIC_LIB)
|
||||
include_directories(
|
||||
SYSTEM
|
||||
${OPENIMAGEDENOISE_INCLUDE_DIRS}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_CYCLES_STANDALONE)
|
||||
set(WITH_CYCLES_DEVICE_OPENCL TRUE)
|
||||
set(WITH_CYCLES_DEVICE_CUDA TRUE)
|
||||
# Experimental and unfinished.
|
||||
set(WITH_CYCLES_NETWORK FALSE)
|
||||
endif()
|
||||
# TODO(sergey): Consider removing it, only causes confusion in interface.
|
||||
set(WITH_CYCLES_DEVICE_MULTI TRUE)
|
||||
@@ -386,18 +392,12 @@ if(WITH_CYCLES_BLENDER)
|
||||
add_subdirectory(blender)
|
||||
endif()
|
||||
|
||||
if(WITH_CYCLES_NETWORK)
|
||||
add_definitions(-DWITH_NETWORK)
|
||||
endif()
|
||||
|
||||
if(WITH_CYCLES_STANDALONE OR WITH_CYCLES_NETWORK OR WITH_CYCLES_CUBIN_COMPILER)
|
||||
add_subdirectory(app)
|
||||
endif()
|
||||
|
||||
add_subdirectory(app)
|
||||
add_subdirectory(bvh)
|
||||
add_subdirectory(device)
|
||||
add_subdirectory(doc)
|
||||
add_subdirectory(graph)
|
||||
add_subdirectory(integrator)
|
||||
add_subdirectory(kernel)
|
||||
add_subdirectory(render)
|
||||
add_subdirectory(subd)
|
||||
|
@@ -90,24 +90,6 @@ if(WITH_CYCLES_STANDALONE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#####################################################################
|
||||
# Cycles network server executable
|
||||
#####################################################################
|
||||
|
||||
if(WITH_CYCLES_NETWORK)
|
||||
set(SRC
|
||||
cycles_server.cpp
|
||||
)
|
||||
add_executable(cycles_server ${SRC})
|
||||
target_link_libraries(cycles_server ${LIBRARIES})
|
||||
cycles_target_link_libraries(cycles_server)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
set_target_properties(cycles_server PROPERTIES INSTALL_RPATH $ORIGIN/lib)
|
||||
endif()
|
||||
unset(SRC)
|
||||
endif()
|
||||
|
||||
#####################################################################
|
||||
# Cycles cubin compiler executable
|
||||
#####################################################################
|
||||
|
@@ -126,7 +126,7 @@ static BufferParams &session_buffer_params()
|
||||
|
||||
static void scene_init()
|
||||
{
|
||||
options.scene = new Scene(options.scene_params, options.session->device);
|
||||
options.scene = options.session->scene;
|
||||
|
||||
/* Read XML */
|
||||
xml_read_file(options.scene, options.filepath.c_str());
|
||||
@@ -148,7 +148,7 @@ static void scene_init()
|
||||
static void session_init()
|
||||
{
|
||||
options.session_params.write_render_cb = write_render;
|
||||
options.session = new Session(options.session_params);
|
||||
options.session = new Session(options.session_params, options.scene_params);
|
||||
|
||||
if (options.session_params.background && !options.quiet)
|
||||
options.session->progress.set_update_callback(function_bind(&session_print_status));
|
||||
@@ -159,7 +159,6 @@ static void session_init()
|
||||
|
||||
/* load scene */
|
||||
scene_init();
|
||||
options.session->scene = options.scene;
|
||||
|
||||
options.session->reset(session_buffer_params(), options.session_params.samples);
|
||||
options.session->start();
|
||||
@@ -527,9 +526,6 @@ static void options_parse(int argc, const char **argv)
|
||||
fprintf(stderr, "No file path specified\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* For smoother Viewport */
|
||||
options.session_params.start_resolution = 64;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -703,7 +703,7 @@ void xml_read_file(Scene *scene, const char *filepath)
|
||||
|
||||
xml_read_include(state, path_filename(filepath));
|
||||
|
||||
scene->params.bvh_type = SceneParams::BVH_STATIC;
|
||||
scene->params.bvh_type = BVH_TYPE_STATIC;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -33,6 +33,7 @@ set(SRC
|
||||
blender_device.cpp
|
||||
blender_image.cpp
|
||||
blender_geometry.cpp
|
||||
blender_gpu_display.cpp
|
||||
blender_light.cpp
|
||||
blender_mesh.cpp
|
||||
blender_object.cpp
|
||||
@@ -50,6 +51,7 @@ set(SRC
|
||||
|
||||
CCL_api.h
|
||||
blender_device.h
|
||||
blender_gpu_display.h
|
||||
blender_id_map.h
|
||||
blender_image.h
|
||||
blender_object_cull.h
|
||||
@@ -93,14 +95,6 @@ set(ADDON_FILES
|
||||
|
||||
add_definitions(${GL_DEFINITIONS})
|
||||
|
||||
if(WITH_CYCLES_DEVICE_OPENCL)
|
||||
add_definitions(-DWITH_OPENCL)
|
||||
endif()
|
||||
|
||||
if(WITH_CYCLES_NETWORK)
|
||||
add_definitions(-DWITH_NETWORK)
|
||||
endif()
|
||||
|
||||
if(WITH_MOD_FLUID)
|
||||
add_definitions(-DWITH_FLUID)
|
||||
endif()
|
||||
|
@@ -58,7 +58,6 @@ class CyclesRender(bpy.types.RenderEngine):
|
||||
bl_use_eevee_viewport = True
|
||||
bl_use_preview = True
|
||||
bl_use_exclude_layers = True
|
||||
bl_use_save_buffers = True
|
||||
bl_use_spherical_stereo = True
|
||||
bl_use_custom_freestyle = True
|
||||
bl_use_alembic_procedural = True
|
||||
@@ -85,6 +84,12 @@ class CyclesRender(bpy.types.RenderEngine):
|
||||
def render(self, depsgraph):
|
||||
engine.render(self, depsgraph)
|
||||
|
||||
def render_frame_finish(self):
|
||||
engine.render_frame_finish(self)
|
||||
|
||||
def draw(self, context, depsgraph):
|
||||
engine.draw(self, depsgraph, context.space_data)
|
||||
|
||||
def bake(self, depsgraph, obj, pass_type, pass_filter, width, height):
|
||||
engine.bake(self, depsgraph, obj, pass_type, pass_filter, width, height)
|
||||
|
||||
@@ -98,7 +103,7 @@ class CyclesRender(bpy.types.RenderEngine):
|
||||
engine.sync(self, depsgraph, context.blend_data)
|
||||
|
||||
def view_draw(self, context, depsgraph):
|
||||
engine.draw(self, depsgraph, context.region, context.space_data, context.region_data)
|
||||
engine.view_draw(self, depsgraph, context.region, context.space_data, context.region_data)
|
||||
|
||||
def update_script_node(self, node):
|
||||
if engine.with_osl():
|
||||
|
@@ -18,62 +18,17 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def _is_using_buggy_driver():
|
||||
import gpu
|
||||
# We need to be conservative here because in multi-GPU systems display card
|
||||
# might be quite old, but others one might be just good.
|
||||
#
|
||||
# So We shouldn't disable possible good dedicated cards just because display
|
||||
# card seems weak. And instead we only blacklist configurations which are
|
||||
# proven to cause problems.
|
||||
if gpu.platform.vendor_get() == "ATI Technologies Inc.":
|
||||
import re
|
||||
version = gpu.platform.version_get()
|
||||
if version.endswith("Compatibility Profile Context"):
|
||||
# Old HD 4xxx and 5xxx series drivers did not have driver version
|
||||
# in the version string, but those cards do not quite work and
|
||||
# causing crashes.
|
||||
return True
|
||||
regex = re.compile(".*Compatibility Profile Context ([0-9]+(\\.[0-9]+)+)$")
|
||||
if not regex.match(version):
|
||||
# Skip cards like FireGL
|
||||
return False
|
||||
version = regex.sub("\\1", version).split('.')
|
||||
return int(version[0]) == 8
|
||||
return False
|
||||
|
||||
|
||||
def _workaround_buggy_drivers():
|
||||
if _is_using_buggy_driver():
|
||||
import _cycles
|
||||
if hasattr(_cycles, "opencl_disable"):
|
||||
print("Cycles: OpenGL driver known to be buggy, disabling OpenCL platform.")
|
||||
_cycles.opencl_disable()
|
||||
|
||||
|
||||
def _configure_argument_parser():
|
||||
import argparse
|
||||
# No help because it conflicts with general Python scripts argument parsing
|
||||
parser = argparse.ArgumentParser(description="Cycles Addon argument parser",
|
||||
add_help=False)
|
||||
parser.add_argument("--cycles-resumable-num-chunks",
|
||||
help="Number of chunks to split sample range into",
|
||||
default=None)
|
||||
parser.add_argument("--cycles-resumable-current-chunk",
|
||||
help="Current chunk of samples range to render",
|
||||
default=None)
|
||||
parser.add_argument("--cycles-resumable-start-chunk",
|
||||
help="Start chunk to render",
|
||||
default=None)
|
||||
parser.add_argument("--cycles-resumable-end-chunk",
|
||||
help="End chunk to render",
|
||||
default=None)
|
||||
parser.add_argument("--cycles-print-stats",
|
||||
help="Print rendering statistics to stderr",
|
||||
action='store_true')
|
||||
parser.add_argument("--cycles-device",
|
||||
help="Set the device to use for Cycles, overriding user preferences and the scene setting."
|
||||
"Valid options are 'CPU', 'CUDA', 'OPTIX' or 'OPENCL'."
|
||||
"Valid options are 'CPU', 'CUDA' or 'OPTIX'."
|
||||
"Additionally, you can append '+CPU' to any GPU type for hybrid rendering.",
|
||||
default=None)
|
||||
return parser
|
||||
@@ -89,21 +44,6 @@ def _parse_command_line():
|
||||
parser = _configure_argument_parser()
|
||||
args, _ = parser.parse_known_args(argv[argv.index("--") + 1:])
|
||||
|
||||
if args.cycles_resumable_num_chunks is not None:
|
||||
if args.cycles_resumable_current_chunk is not None:
|
||||
import _cycles
|
||||
_cycles.set_resumable_chunk(
|
||||
int(args.cycles_resumable_num_chunks),
|
||||
int(args.cycles_resumable_current_chunk),
|
||||
)
|
||||
elif args.cycles_resumable_start_chunk is not None and \
|
||||
args.cycles_resumable_end_chunk:
|
||||
import _cycles
|
||||
_cycles.set_resumable_chunk_range(
|
||||
int(args.cycles_resumable_num_chunks),
|
||||
int(args.cycles_resumable_start_chunk),
|
||||
int(args.cycles_resumable_end_chunk),
|
||||
)
|
||||
if args.cycles_print_stats:
|
||||
import _cycles
|
||||
_cycles.enable_print_stats()
|
||||
@@ -118,23 +58,11 @@ def init():
|
||||
import _cycles
|
||||
import os.path
|
||||
|
||||
# Workaround possibly buggy legacy drivers which crashes on the OpenCL
|
||||
# device enumeration.
|
||||
#
|
||||
# This checks are not really correct because they might still fail
|
||||
# in the case of multiple GPUs. However, currently buggy drivers
|
||||
# are really old and likely to be used in single GPU systems only
|
||||
# anyway.
|
||||
#
|
||||
# Can't do it in the background mode, so we hope OpenCL is no enabled
|
||||
# in the user preferences.
|
||||
if not bpy.app.background:
|
||||
_workaround_buggy_drivers()
|
||||
|
||||
path = os.path.dirname(__file__)
|
||||
user_path = os.path.dirname(os.path.abspath(bpy.utils.user_resource('CONFIG', path='')))
|
||||
temp_path = bpy.app.tempdir
|
||||
|
||||
_cycles.init(path, user_path, bpy.app.background)
|
||||
_cycles.init(path, user_path, temp_path, bpy.app.background)
|
||||
_parse_command_line()
|
||||
|
||||
|
||||
@@ -177,6 +105,25 @@ def render(engine, depsgraph):
|
||||
_cycles.render(engine.session, depsgraph.as_pointer())
|
||||
|
||||
|
||||
def render_frame_finish(engine):
|
||||
if not engine.session:
|
||||
return
|
||||
|
||||
import _cycles
|
||||
_cycles.render_frame_finish(engine.session)
|
||||
|
||||
def draw(engine, depsgraph, space_image):
|
||||
if not engine.session:
|
||||
return
|
||||
|
||||
depsgraph_ptr = depsgraph.as_pointer()
|
||||
space_image_ptr = space_image.as_pointer()
|
||||
screen_ptr = space_image.id_data.as_pointer()
|
||||
|
||||
import _cycles
|
||||
_cycles.draw(engine.session, depsgraph_ptr, screen_ptr, space_image_ptr)
|
||||
|
||||
|
||||
def bake(engine, depsgraph, obj, pass_type, pass_filter, width, height):
|
||||
import _cycles
|
||||
session = getattr(engine, "session", None)
|
||||
@@ -204,14 +151,14 @@ def sync(engine, depsgraph, data):
|
||||
_cycles.sync(engine.session, depsgraph.as_pointer())
|
||||
|
||||
|
||||
def draw(engine, depsgraph, region, v3d, rv3d):
|
||||
def view_draw(engine, depsgraph, region, v3d, rv3d):
|
||||
import _cycles
|
||||
depsgraph = depsgraph.as_pointer()
|
||||
v3d = v3d.as_pointer()
|
||||
rv3d = rv3d.as_pointer()
|
||||
|
||||
# draw render image
|
||||
_cycles.draw(engine.session, depsgraph, v3d, rv3d)
|
||||
_cycles.view_draw(engine.session, depsgraph, v3d, rv3d)
|
||||
|
||||
|
||||
def available_devices():
|
||||
@@ -224,11 +171,6 @@ def with_osl():
|
||||
return _cycles.with_osl
|
||||
|
||||
|
||||
def with_network():
|
||||
import _cycles
|
||||
return _cycles.with_network
|
||||
|
||||
|
||||
def system_info():
|
||||
import _cycles
|
||||
return _cycles.system_info()
|
||||
@@ -243,6 +185,7 @@ def list_render_passes(scene, srl):
|
||||
# Data passes.
|
||||
if srl.use_pass_z: yield ("Depth", "Z", 'VALUE')
|
||||
if srl.use_pass_mist: yield ("Mist", "Z", 'VALUE')
|
||||
if srl.use_pass_position: yield ("Position", "XYZ", 'VECTOR')
|
||||
if srl.use_pass_normal: yield ("Normal", "XYZ", 'VECTOR')
|
||||
if srl.use_pass_vector: yield ("Vector", "XYZW", 'VECTOR')
|
||||
if srl.use_pass_uv: yield ("UV", "UVA", 'VECTOR')
|
||||
@@ -265,6 +208,7 @@ def list_render_passes(scene, srl):
|
||||
if srl.use_pass_environment: yield ("Env", "RGB", 'COLOR')
|
||||
if srl.use_pass_shadow: yield ("Shadow", "RGB", 'COLOR')
|
||||
if srl.use_pass_ambient_occlusion: yield ("AO", "RGB", 'COLOR')
|
||||
if crl.use_pass_shadow_catcher: yield ("Shadow Catcher", "RGB", 'COLOR')
|
||||
|
||||
# Debug passes.
|
||||
if crl.pass_debug_render_time: yield ("Debug Render Time", "X", 'VALUE')
|
||||
@@ -283,30 +227,20 @@ def list_render_passes(scene, srl):
|
||||
yield ("CryptoAsset" + '{:02d}'.format(i), "RGBA", 'COLOR')
|
||||
|
||||
# Denoising passes.
|
||||
if (scene.cycles.use_denoising and crl.use_denoising) or crl.denoising_store_passes:
|
||||
if scene.cycles.use_denoising and crl.use_denoising:
|
||||
yield ("Noisy Image", "RGBA", 'COLOR')
|
||||
if crl.denoising_store_passes:
|
||||
yield ("Denoising Normal", "XYZ", 'VECTOR')
|
||||
yield ("Denoising Albedo", "RGB", 'COLOR')
|
||||
yield ("Denoising Depth", "Z", 'VALUE')
|
||||
|
||||
if scene.cycles.denoiser == 'NLM':
|
||||
yield ("Denoising Shadowing", "X", 'VALUE')
|
||||
yield ("Denoising Variance", "RGB", 'COLOR')
|
||||
yield ("Denoising Intensity", "X", 'VALUE')
|
||||
|
||||
clean_options = ("denoising_diffuse_direct", "denoising_diffuse_indirect",
|
||||
"denoising_glossy_direct", "denoising_glossy_indirect",
|
||||
"denoising_transmission_direct", "denoising_transmission_indirect")
|
||||
if any(getattr(crl, option) for option in clean_options):
|
||||
yield ("Denoising Clean", "RGB", 'COLOR')
|
||||
if crl.use_pass_shadow_catcher:
|
||||
yield ("Noisy Shadow Catcher", "RGBA", 'COLOR')
|
||||
if crl.denoising_store_passes:
|
||||
yield ("Denoising Normal", "XYZ", 'VECTOR')
|
||||
yield ("Denoising Albedo", "RGB", 'COLOR')
|
||||
|
||||
# Custom AOV passes.
|
||||
for aov in srl.aovs:
|
||||
if aov.type == 'VALUE':
|
||||
yield (aov.name, "X", 'VALUE')
|
||||
else:
|
||||
yield (aov.name, "RGBA", 'COLOR')
|
||||
yield (aov.name, "RGB", 'COLOR')
|
||||
|
||||
|
||||
def register_passes(engine, scene, view_layer):
|
||||
|
@@ -60,32 +60,48 @@ class AddPresetSampling(AddPresetBase, Operator):
|
||||
]
|
||||
|
||||
preset_values = [
|
||||
"cycles.use_adaptive_sampling",
|
||||
"cycles.samples",
|
||||
"cycles.preview_samples",
|
||||
"cycles.aa_samples",
|
||||
"cycles.preview_aa_samples",
|
||||
"cycles.diffuse_samples",
|
||||
"cycles.glossy_samples",
|
||||
"cycles.transmission_samples",
|
||||
"cycles.ao_samples",
|
||||
"cycles.mesh_light_samples",
|
||||
"cycles.subsurface_samples",
|
||||
"cycles.volume_samples",
|
||||
"cycles.use_square_samples",
|
||||
"cycles.progressive",
|
||||
"cycles.seed",
|
||||
"cycles.sample_clamp_direct",
|
||||
"cycles.sample_clamp_indirect",
|
||||
"cycles.sample_all_lights_direct",
|
||||
"cycles.sample_all_lights_indirect",
|
||||
"cycles.adaptive_threshold",
|
||||
"cycles.adaptive_min_samples",
|
||||
"cycles.time_limit",
|
||||
"cycles.use_denoising",
|
||||
"cycles.denoiser",
|
||||
"cycles.denoising_input_passes",
|
||||
"cycles.denoising_prefilter",
|
||||
]
|
||||
|
||||
preset_subdir = "cycles/sampling"
|
||||
|
||||
|
||||
class AddPresetViewportSampling(AddPresetBase, Operator):
|
||||
'''Add a Viewport Sampling Preset'''
|
||||
bl_idname = "render.cycles_viewport_sampling_preset_add"
|
||||
bl_label = "Add Viewport Sampling Preset"
|
||||
preset_menu = "CYCLES_PT_viewport_sampling_presets"
|
||||
|
||||
preset_defines = [
|
||||
"cycles = bpy.context.scene.cycles"
|
||||
]
|
||||
|
||||
preset_values = [
|
||||
"cycles.use_preview_adaptive_sampling",
|
||||
"cycles.preview_samples",
|
||||
"cycles.preview_adaptive_threshold",
|
||||
"cycles.preview_adaptive_min_samples",
|
||||
"cycles.use_preview_denoising",
|
||||
"cycles.preview_denoiser",
|
||||
"cycles.preview_denoising_input_passes",
|
||||
"cycles.preview_denoising_prefilter",
|
||||
"cycles.preview_denoising_start_sample",
|
||||
]
|
||||
|
||||
preset_subdir = "cycles/viewport_sampling"
|
||||
|
||||
classes = (
|
||||
AddPresetIntegrator,
|
||||
AddPresetSampling,
|
||||
AddPresetViewportSampling,
|
||||
)
|
||||
|
||||
|
||||
|
@@ -39,11 +39,6 @@ enum_devices = (
|
||||
('GPU', "GPU Compute", "Use GPU compute device for rendering, configured in the system tab in the user preferences"),
|
||||
)
|
||||
|
||||
from _cycles import with_network
|
||||
if with_network:
|
||||
enum_devices += (('NETWORK', "Networked Device", "Use networked device for rendering"),)
|
||||
del with_network
|
||||
|
||||
enum_feature_set = (
|
||||
('SUPPORTED', "Supported", "Only use finished and supported features"),
|
||||
('EXPERIMENTAL', "Experimental", "Use experimental and incomplete features that might be broken or change in the future", 'ERROR', 1),
|
||||
@@ -84,15 +79,6 @@ enum_curve_shape = (
|
||||
('THICK', "3D Curves", "Render hair as 3D curve, for accurate results when viewing hair close up"),
|
||||
)
|
||||
|
||||
enum_tile_order = (
|
||||
('CENTER', "Center", "Render from center to the edges"),
|
||||
('RIGHT_TO_LEFT', "Right to Left", "Render from right to left"),
|
||||
('LEFT_TO_RIGHT', "Left to Right", "Render from left to right"),
|
||||
('TOP_TO_BOTTOM', "Top to Bottom", "Render from top to bottom"),
|
||||
('BOTTOM_TO_TOP', "Bottom to Top", "Render from bottom to top"),
|
||||
('HILBERT_SPIRAL', "Hilbert Spiral", "Render in a Hilbert Spiral"),
|
||||
)
|
||||
|
||||
enum_use_layer_samples = (
|
||||
('USE', "Use", "Per render layer number of samples override scene samples"),
|
||||
('BOUNDED', "Bounded", "Bound per render layer number of samples by global samples"),
|
||||
@@ -101,15 +87,9 @@ enum_use_layer_samples = (
|
||||
|
||||
enum_sampling_pattern = (
|
||||
('SOBOL', "Sobol", "Use Sobol random sampling pattern"),
|
||||
('CORRELATED_MUTI_JITTER', "Correlated Multi-Jitter", "Use Correlated Multi-Jitter random sampling pattern"),
|
||||
('PROGRESSIVE_MUTI_JITTER', "Progressive Multi-Jitter", "Use Progressive Multi-Jitter random sampling pattern"),
|
||||
)
|
||||
|
||||
enum_integrator = (
|
||||
('BRANCHED_PATH', "Branched Path Tracing", "Path tracing integrator that branches on the first bounce, giving more control over the number of light and material samples"),
|
||||
('PATH', "Path Tracing", "Pure path tracing integrator"),
|
||||
)
|
||||
|
||||
enum_volume_sampling = (
|
||||
('DISTANCE', "Distance", "Use distance sampling, best for dense volumes with lights far away"),
|
||||
('EQUIANGULAR', "Equiangular", "Use equiangular sampling, best for volumes with low density with light inside or near the volume"),
|
||||
@@ -131,7 +111,6 @@ enum_device_type = (
|
||||
('CPU', "CPU", "CPU", 0),
|
||||
('CUDA', "CUDA", "CUDA", 1),
|
||||
('OPTIX', "OptiX", "OptiX", 3),
|
||||
('OPENCL', "OpenCL", "OpenCL", 2)
|
||||
)
|
||||
|
||||
enum_texture_limit = (
|
||||
@@ -144,39 +123,46 @@ enum_texture_limit = (
|
||||
('4096', "4096", "Limit texture size to 4096 pixels", 6),
|
||||
('8192', "8192", "Limit texture size to 8192 pixels", 7),
|
||||
)
|
||||
|
||||
|
||||
# NOTE: Identifiers are expected to be an upper case version of identifiers from `Pass::get_type_enum()`
|
||||
enum_view3d_shading_render_pass = (
|
||||
('', "General", ""),
|
||||
|
||||
('COMBINED', "Combined", "Show the Combined Render pass", 1),
|
||||
('EMISSION', "Emission", "Show the Emission render pass", 33),
|
||||
('BACKGROUND', "Background", "Show the Background render pass", 34),
|
||||
('AO', "Ambient Occlusion", "Show the Ambient Occlusion render pass", 35),
|
||||
('COMBINED', "Combined", "Show the Combined Render pass"),
|
||||
('EMISSION', "Emission", "Show the Emission render pass"),
|
||||
('BACKGROUND', "Background", "Show the Background render pass"),
|
||||
('AO', "Ambient Occlusion", "Show the Ambient Occlusion render pass"),
|
||||
('SHADOW', "Shadow", "Show the Shadow render pass"),
|
||||
('SHADOW_CATCHER', "Shadow Catcher", "Show the Shadow Catcher render pass"),
|
||||
|
||||
('', "Light", ""),
|
||||
|
||||
('DIFFUSE_DIRECT', "Diffuse Direct", "Show the Diffuse Direct render pass", 38),
|
||||
('DIFFUSE_INDIRECT', "Diffuse Indirect", "Show the Diffuse Indirect render pass", 39),
|
||||
('DIFFUSE_COLOR', "Diffuse Color", "Show the Diffuse Color render pass", 40),
|
||||
('DIFFUSE_DIRECT', "Diffuse Direct", "Show the Diffuse Direct render pass"),
|
||||
('DIFFUSE_INDIRECT', "Diffuse Indirect", "Show the Diffuse Indirect render pass"),
|
||||
('DIFFUSE_COLOR', "Diffuse Color", "Show the Diffuse Color render pass"),
|
||||
|
||||
('GLOSSY_DIRECT', "Glossy Direct", "Show the Glossy Direct render pass", 41),
|
||||
('GLOSSY_INDIRECT', "Glossy Indirect", "Show the Glossy Indirect render pass", 42),
|
||||
('GLOSSY_COLOR', "Glossy Color", "Show the Glossy Color render pass", 43),
|
||||
('GLOSSY_DIRECT', "Glossy Direct", "Show the Glossy Direct render pass"),
|
||||
('GLOSSY_INDIRECT', "Glossy Indirect", "Show the Glossy Indirect render pass"),
|
||||
('GLOSSY_COLOR', "Glossy Color", "Show the Glossy Color render pass"),
|
||||
|
||||
('', "", ""),
|
||||
|
||||
('TRANSMISSION_DIRECT', "Transmission Direct", "Show the Transmission Direct render pass", 44),
|
||||
('TRANSMISSION_INDIRECT', "Transmission Indirect", "Show the Transmission Indirect render pass", 45),
|
||||
('TRANSMISSION_COLOR', "Transmission Color", "Show the Transmission Color render pass", 46),
|
||||
('TRANSMISSION_DIRECT', "Transmission Direct", "Show the Transmission Direct render pass"),
|
||||
('TRANSMISSION_INDIRECT', "Transmission Indirect", "Show the Transmission Indirect render pass"),
|
||||
('TRANSMISSION_COLOR', "Transmission Color", "Show the Transmission Color render pass"),
|
||||
|
||||
('VOLUME_DIRECT', "Volume Direct", "Show the Volume Direct render pass", 50),
|
||||
('VOLUME_INDIRECT', "Volume Indirect", "Show the Volume Indirect render pass", 51),
|
||||
('VOLUME_DIRECT', "Volume Direct", "Show the Volume Direct render pass"),
|
||||
('VOLUME_INDIRECT', "Volume Indirect", "Show the Volume Indirect render pass"),
|
||||
|
||||
('', "Data", ""),
|
||||
|
||||
('NORMAL', "Normal", "Show the Normal render pass", 3),
|
||||
('UV', "UV", "Show the UV render pass", 4),
|
||||
('MIST', "Mist", "Show the Mist render pass", 32),
|
||||
('POSITION', "Position", "Show the Position render pass"),
|
||||
('NORMAL', "Normal", "Show the Normal render pass"),
|
||||
('UV', "UV", "Show the UV render pass"),
|
||||
('MIST', "Mist", "Show the Mist render pass"),
|
||||
('DENOISING_ALBEDO', "Denoising Albedo", "Albedo pass used by denoiser"),
|
||||
('DENOISING_NORMAL', "Denoising Normal", "Normal pass used by denoiser"),
|
||||
('SAMPLE_COUNT', "Sample Count", "Per-pixel number of samples"),
|
||||
)
|
||||
|
||||
|
||||
@@ -208,18 +194,23 @@ def enum_preview_denoiser(self, context):
|
||||
|
||||
|
||||
def enum_denoiser(self, context):
|
||||
items = [('NLM', "NLM", "Cycles native non-local means denoiser, running on any compute device", 1)]
|
||||
items = []
|
||||
items += enum_optix_denoiser(self, context)
|
||||
items += enum_openimagedenoise_denoiser(self, context)
|
||||
return items
|
||||
|
||||
|
||||
enum_denoising_input_passes = (
|
||||
('RGB', "Color", "Use only color as input", 1),
|
||||
('RGB_ALBEDO', "Color + Albedo", "Use color and albedo data as input", 2),
|
||||
('RGB_ALBEDO_NORMAL', "Color + Albedo + Normal", "Use color, albedo and normal data as input", 3),
|
||||
('RGB', "None", "Don't use utility passes for denoising", 1),
|
||||
('RGB_ALBEDO', "Albedo", "Use albedo pass for denoising", 2),
|
||||
('RGB_ALBEDO_NORMAL', "Albedo and Normal", "Use albedo and normal passes for denoising", 3),
|
||||
)
|
||||
|
||||
enum_denoising_prefilter = (
|
||||
('NONE', "None", "No prefiltering, use when guiding passes are noise-free", 1),
|
||||
('FAST', "Fast", "Denoise color and guiding passes together. Improves quality when guiding passes are noisy using least amount of extra processing time", 2),
|
||||
('ACCURATE', "Accurate", "Prefilter noisy guiding passes before denoising color. Improves quality when guiding passes are noisy using extra processing time", 3),
|
||||
)
|
||||
|
||||
def update_render_passes(self, context):
|
||||
scene = context.scene
|
||||
@@ -252,13 +243,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
description="Use Open Shading Language (CPU rendering only)",
|
||||
)
|
||||
|
||||
progressive: EnumProperty(
|
||||
name="Integrator",
|
||||
description="Method to sample lights and materials",
|
||||
items=enum_integrator,
|
||||
default='PATH',
|
||||
)
|
||||
|
||||
preview_pause: BoolProperty(
|
||||
name="Pause Preview",
|
||||
description="Pause all viewport preview renders",
|
||||
@@ -268,110 +252,88 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
use_denoising: BoolProperty(
|
||||
name="Use Denoising",
|
||||
description="Denoise the rendered image",
|
||||
default=False,
|
||||
default=True,
|
||||
update=update_render_passes,
|
||||
)
|
||||
denoiser: EnumProperty(
|
||||
name="Denoiser",
|
||||
description="Denoise the image with the selected denoiser. "
|
||||
"For denoising the image after rendering",
|
||||
items=enum_denoiser,
|
||||
default=4, # Use integer to avoid error in builds without OpenImageDenoise.
|
||||
update=update_render_passes,
|
||||
)
|
||||
denoising_prefilter: EnumProperty(
|
||||
name="Denoising Prefilter",
|
||||
description="Prefilter noisy guiding (albedo and normal) passes to improve denoising quality when using OpenImageDenoiser",
|
||||
items=enum_denoising_prefilter,
|
||||
default='ACCURATE',
|
||||
)
|
||||
denoising_input_passes: EnumProperty(
|
||||
name="Denoising Input Passes",
|
||||
description="Passes used by the denoiser to distinguish noise from shader and geometry detail",
|
||||
items=enum_denoising_input_passes,
|
||||
default='RGB_ALBEDO_NORMAL',
|
||||
)
|
||||
|
||||
use_preview_denoising: BoolProperty(
|
||||
name="Use Viewport Denoising",
|
||||
description="Denoise the image in the 3D viewport",
|
||||
default=False,
|
||||
)
|
||||
|
||||
denoiser: EnumProperty(
|
||||
name="Denoiser",
|
||||
description="Denoise the image with the selected denoiser. "
|
||||
"For denoising the image after rendering, denoising data render passes "
|
||||
"also adapt to the selected denoiser",
|
||||
items=enum_denoiser,
|
||||
default=1,
|
||||
update=update_render_passes,
|
||||
)
|
||||
preview_denoiser: EnumProperty(
|
||||
name="Viewport Denoiser",
|
||||
description="Denoise the image after each preview update with the selected denoiser",
|
||||
items=enum_preview_denoiser,
|
||||
default=0,
|
||||
)
|
||||
|
||||
use_square_samples: BoolProperty(
|
||||
name="Square Samples",
|
||||
description="Square sampling values for easier artist control",
|
||||
default=False,
|
||||
preview_denoising_prefilter: EnumProperty(
|
||||
name="Viewport Denoising Prefilter",
|
||||
description="Prefilter noisy guiding (albedo and normal) passes to improve denoising quality when using OpenImageDenoiser",
|
||||
items=enum_denoising_prefilter,
|
||||
default='FAST',
|
||||
)
|
||||
preview_denoising_input_passes: EnumProperty(
|
||||
name="Viewport Denoising Input Passes",
|
||||
description="Passes used by the denoiser to distinguish noise from shader and geometry detail",
|
||||
items=enum_denoising_input_passes,
|
||||
default='RGB_ALBEDO',
|
||||
)
|
||||
preview_denoising_start_sample: IntProperty(
|
||||
name="Start Denoising",
|
||||
description="Sample to start denoising the preview at",
|
||||
min=0, max=(1 << 24),
|
||||
default=1,
|
||||
)
|
||||
|
||||
samples: IntProperty(
|
||||
name="Samples",
|
||||
description="Number of samples to render for each pixel",
|
||||
min=1, max=(1 << 24),
|
||||
default=128,
|
||||
default=4096,
|
||||
)
|
||||
preview_samples: IntProperty(
|
||||
name="Viewport Samples",
|
||||
description="Number of samples to render in the viewport, unlimited if 0",
|
||||
min=0, max=(1 << 24),
|
||||
default=32,
|
||||
)
|
||||
aa_samples: IntProperty(
|
||||
name="AA Samples",
|
||||
description="Number of antialiasing samples to render for each pixel",
|
||||
min=1, max=2097151,
|
||||
default=128,
|
||||
)
|
||||
preview_aa_samples: IntProperty(
|
||||
name="AA Samples",
|
||||
description="Number of antialiasing samples to render in the viewport, unlimited if 0",
|
||||
min=0, max=2097151,
|
||||
default=32,
|
||||
default=1024,
|
||||
)
|
||||
|
||||
diffuse_samples: IntProperty(
|
||||
name="Diffuse Samples",
|
||||
description="Number of diffuse bounce samples to render for each AA sample",
|
||||
min=1, max=1024,
|
||||
default=1,
|
||||
)
|
||||
glossy_samples: IntProperty(
|
||||
name="Glossy Samples",
|
||||
description="Number of glossy bounce samples to render for each AA sample",
|
||||
min=1, max=1024,
|
||||
default=1,
|
||||
)
|
||||
transmission_samples: IntProperty(
|
||||
name="Transmission Samples",
|
||||
description="Number of transmission bounce samples to render for each AA sample",
|
||||
min=1, max=1024,
|
||||
default=1,
|
||||
)
|
||||
ao_samples: IntProperty(
|
||||
name="Ambient Occlusion Samples",
|
||||
description="Number of ambient occlusion samples to render for each AA sample",
|
||||
min=1, max=1024,
|
||||
default=1,
|
||||
)
|
||||
mesh_light_samples: IntProperty(
|
||||
name="Mesh Light Samples",
|
||||
description="Number of mesh emission light samples to render for each AA sample",
|
||||
min=1, max=1024,
|
||||
default=1,
|
||||
)
|
||||
subsurface_samples: IntProperty(
|
||||
name="Subsurface Samples",
|
||||
description="Number of subsurface scattering samples to render for each AA sample",
|
||||
min=1, max=1024,
|
||||
default=1,
|
||||
)
|
||||
volume_samples: IntProperty(
|
||||
name="Volume Samples",
|
||||
description="Number of volume scattering samples to render for each AA sample",
|
||||
min=1, max=1024,
|
||||
default=1,
|
||||
time_limit: FloatProperty(
|
||||
name="Time Limit",
|
||||
description="Limit the render time (excluding synchronization time)."
|
||||
"Zero disables the limit",
|
||||
min=0.0,
|
||||
default=0.0,
|
||||
step=100.0,
|
||||
unit='TIME_ABSOLUTE',
|
||||
)
|
||||
|
||||
sampling_pattern: EnumProperty(
|
||||
name="Sampling Pattern",
|
||||
description="Random sampling pattern used by the integrator",
|
||||
items=enum_sampling_pattern,
|
||||
default='SOBOL',
|
||||
default='PROGRESSIVE_MUTI_JITTER',
|
||||
)
|
||||
|
||||
use_layer_samples: EnumProperty(
|
||||
@@ -381,17 +343,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
default='USE',
|
||||
)
|
||||
|
||||
sample_all_lights_direct: BoolProperty(
|
||||
name="Sample All Direct Lights",
|
||||
description="Sample all lights (for direct samples), rather than randomly picking one",
|
||||
default=True,
|
||||
)
|
||||
|
||||
sample_all_lights_indirect: BoolProperty(
|
||||
name="Sample All Indirect Lights",
|
||||
description="Sample all lights (for indirect samples), rather than randomly picking one",
|
||||
default=True,
|
||||
)
|
||||
light_sampling_threshold: FloatProperty(
|
||||
name="Light Sampling Threshold",
|
||||
description="Probabilistically terminate light samples when the light contribution is below this threshold (more noise but faster rendering). "
|
||||
@@ -403,19 +354,39 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
use_adaptive_sampling: BoolProperty(
|
||||
name="Use Adaptive Sampling",
|
||||
description="Automatically reduce the number of samples per pixel based on estimated noise level",
|
||||
default=False,
|
||||
default=True,
|
||||
)
|
||||
|
||||
adaptive_threshold: FloatProperty(
|
||||
name="Adaptive Sampling Threshold",
|
||||
description="Noise level step to stop sampling at, lower values reduce noise at the cost of render time. Zero for automatic setting based on number of AA samples",
|
||||
min=0.0, max=1.0,
|
||||
default=0.0,
|
||||
soft_min=0.001,
|
||||
default=0.01,
|
||||
precision=4,
|
||||
)
|
||||
adaptive_min_samples: IntProperty(
|
||||
name="Adaptive Min Samples",
|
||||
description="Minimum AA samples for adaptive sampling, to discover noisy features before stopping sampling. Zero for automatic setting based on number of AA samples",
|
||||
description="Minimum AA samples for adaptive sampling, to discover noisy features before stopping sampling. Zero for automatic setting based on noise threshold",
|
||||
min=0, max=4096,
|
||||
default=0,
|
||||
)
|
||||
|
||||
use_preview_adaptive_sampling: BoolProperty(
|
||||
name="Use Adaptive Sampling",
|
||||
description="Automatically reduce the number of samples per pixel based on estimated noise level, for viewport renders",
|
||||
default=True,
|
||||
)
|
||||
preview_adaptive_threshold: FloatProperty(
|
||||
name="Adaptive Sampling Threshold",
|
||||
description="Noise level step to stop sampling at, lower values reduce noise at the cost of render time. Zero for automatic setting based on number of AA samples, for viewport renders",
|
||||
min=0.0, max=1.0,
|
||||
soft_min=0.001,
|
||||
default=0.1,
|
||||
precision=4,
|
||||
)
|
||||
preview_adaptive_min_samples: IntProperty(
|
||||
name="Adaptive Min Samples",
|
||||
description="Minimum AA samples for adaptive sampling, to discover noisy features before stopping sampling. Zero for automatic setting based on noise threshold, for viewport renders",
|
||||
min=0, max=4096,
|
||||
default=0,
|
||||
)
|
||||
@@ -632,53 +603,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
default=10.0,
|
||||
)
|
||||
|
||||
debug_tile_size: IntProperty(
|
||||
name="Tile Size",
|
||||
description="",
|
||||
min=1, max=4096,
|
||||
default=1024,
|
||||
)
|
||||
|
||||
preview_start_resolution: IntProperty(
|
||||
name="Start Resolution",
|
||||
description="Resolution to start rendering preview at, "
|
||||
"progressively increasing it to the full viewport size",
|
||||
min=8, max=16384,
|
||||
default=64,
|
||||
subtype='PIXEL'
|
||||
)
|
||||
preview_denoising_start_sample: IntProperty(
|
||||
name="Start Denoising",
|
||||
description="Sample to start denoising the preview at",
|
||||
min=0, max=(1 << 24),
|
||||
default=1,
|
||||
)
|
||||
preview_denoising_input_passes: EnumProperty(
|
||||
name="Viewport Input Passes",
|
||||
description="Passes used by the denoiser to distinguish noise from shader and geometry detail",
|
||||
items=enum_denoising_input_passes,
|
||||
default='RGB_ALBEDO',
|
||||
)
|
||||
|
||||
debug_reset_timeout: FloatProperty(
|
||||
name="Reset timeout",
|
||||
description="",
|
||||
min=0.01, max=10.0,
|
||||
default=0.1,
|
||||
)
|
||||
debug_cancel_timeout: FloatProperty(
|
||||
name="Cancel timeout",
|
||||
description="",
|
||||
min=0.01, max=10.0,
|
||||
default=0.1,
|
||||
)
|
||||
debug_text_timeout: FloatProperty(
|
||||
name="Text timeout",
|
||||
description="",
|
||||
min=0.01, max=10.0,
|
||||
default=1.0,
|
||||
)
|
||||
|
||||
debug_bvh_type: EnumProperty(
|
||||
name="Viewport BVH Type",
|
||||
description="Choose between faster updates, or faster render",
|
||||
@@ -701,38 +625,24 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
default=0,
|
||||
min=0, max=16,
|
||||
)
|
||||
tile_order: EnumProperty(
|
||||
name="Tile Order",
|
||||
description="Tile order for rendering",
|
||||
items=enum_tile_order,
|
||||
default='HILBERT_SPIRAL',
|
||||
options=set(), # Not animatable!
|
||||
)
|
||||
use_progressive_refine: BoolProperty(
|
||||
name="Progressive Refine",
|
||||
description="Instead of rendering each tile until it is finished, "
|
||||
"refine the whole image progressively "
|
||||
"(this renders somewhat slower, "
|
||||
"but time can be saved by manually stopping the render when the noise is low enough)",
|
||||
default=False,
|
||||
)
|
||||
|
||||
bake_type: EnumProperty(
|
||||
name="Bake Type",
|
||||
default='COMBINED',
|
||||
description="Type of pass to bake",
|
||||
items=(
|
||||
('COMBINED', "Combined", ""),
|
||||
('AO', "Ambient Occlusion", ""),
|
||||
('SHADOW', "Shadow", ""),
|
||||
('NORMAL', "Normal", ""),
|
||||
('UV', "UV", ""),
|
||||
('ROUGHNESS', "Roughness", ""),
|
||||
('EMIT', "Emit", ""),
|
||||
('ENVIRONMENT', "Environment", ""),
|
||||
('DIFFUSE', "Diffuse", ""),
|
||||
('GLOSSY', "Glossy", ""),
|
||||
('TRANSMISSION', "Transmission", ""),
|
||||
('COMBINED', "Combined", "", 0),
|
||||
('AO', "Ambient Occlusion", "", 1),
|
||||
('SHADOW', "Shadow", "", 2),
|
||||
('POSITION', "Position", "", 11),
|
||||
('NORMAL', "Normal", "", 3),
|
||||
('UV', "UV", "", 4),
|
||||
('ROUGHNESS', "Roughness", "", 5),
|
||||
('EMIT', "Emit", "", 6),
|
||||
('ENVIRONMENT', "Environment", "", 7),
|
||||
('DIFFUSE', "Diffuse", "", 8),
|
||||
('GLOSSY', "Glossy", "", 9),
|
||||
('TRANSMISSION', "Transmission", "", 10),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -827,6 +737,18 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
min=0, max=1024,
|
||||
)
|
||||
|
||||
use_auto_tile: BoolProperty(
|
||||
name="Auto Tiles",
|
||||
description="Automatically split image into tiles",
|
||||
default=True,
|
||||
)
|
||||
tile_size: IntProperty(
|
||||
name="Tile Size",
|
||||
default=2048,
|
||||
description="",
|
||||
min=0, max=16384,
|
||||
)
|
||||
|
||||
# Various fine-tuning debug flags
|
||||
|
||||
def _devices_update_callback(self, context):
|
||||
@@ -844,45 +766,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
items=enum_bvh_layouts,
|
||||
default='EMBREE',
|
||||
)
|
||||
debug_use_cpu_split_kernel: BoolProperty(name="Split Kernel", default=False)
|
||||
|
||||
debug_use_cuda_adaptive_compile: BoolProperty(name="Adaptive Compile", default=False)
|
||||
debug_use_cuda_split_kernel: BoolProperty(name="Split Kernel", default=False)
|
||||
|
||||
debug_optix_cuda_streams: IntProperty(name="CUDA Streams", default=1, min=1)
|
||||
debug_optix_curves_api: BoolProperty(name="Native OptiX Curve Primitive", default=False)
|
||||
|
||||
debug_opencl_kernel_type: EnumProperty(
|
||||
name="OpenCL Kernel Type",
|
||||
default='DEFAULT',
|
||||
items=(
|
||||
('DEFAULT', "Default", ""),
|
||||
('MEGA', "Mega", ""),
|
||||
('SPLIT', "Split", ""),
|
||||
),
|
||||
update=CyclesRenderSettings._devices_update_callback
|
||||
)
|
||||
|
||||
debug_opencl_device_type: EnumProperty(
|
||||
name="OpenCL Device Type",
|
||||
default='ALL',
|
||||
items=(
|
||||
('NONE', "None", ""),
|
||||
('ALL', "All", ""),
|
||||
('DEFAULT', "Default", ""),
|
||||
('CPU', "CPU", ""),
|
||||
('GPU', "GPU", ""),
|
||||
('ACCELERATOR', "Accelerator", ""),
|
||||
),
|
||||
update=CyclesRenderSettings._devices_update_callback
|
||||
)
|
||||
|
||||
debug_use_opencl_debug: BoolProperty(name="Debug OpenCL", default=False)
|
||||
|
||||
debug_opencl_mem_limit: IntProperty(
|
||||
name="Memory limit",
|
||||
default=0,
|
||||
description="Artificial limit on OpenCL memory usage in MB (0 to disable limit)"
|
||||
debug_use_optix_debug: BoolProperty(
|
||||
name="OptiX Module Debug",
|
||||
description="Load OptiX module in debug mode: lower logging verbosity level, enable validations, and lower optimization level",
|
||||
default=False
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@@ -1031,12 +921,6 @@ class CyclesLightSettings(bpy.types.PropertyGroup):
|
||||
description="Light casts shadows",
|
||||
default=True,
|
||||
)
|
||||
samples: IntProperty(
|
||||
name="Samples",
|
||||
description="Number of light samples to render for each AA sample",
|
||||
min=1, max=10000,
|
||||
default=1,
|
||||
)
|
||||
max_bounces: IntProperty(
|
||||
name="Max Bounces",
|
||||
description="Maximum number of bounces the light will contribute to the render",
|
||||
@@ -1084,12 +968,6 @@ class CyclesWorldSettings(bpy.types.PropertyGroup):
|
||||
min=4, max=8192,
|
||||
default=1024,
|
||||
)
|
||||
samples: IntProperty(
|
||||
name="Samples",
|
||||
description="Number of light samples to render for each AA sample",
|
||||
min=1, max=10000,
|
||||
default=1,
|
||||
)
|
||||
max_bounces: IntProperty(
|
||||
name="Max Bounces",
|
||||
description="Maximum number of bounces the background light will contribute to the render",
|
||||
@@ -1343,91 +1221,25 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
|
||||
update=update_render_passes,
|
||||
)
|
||||
|
||||
use_pass_shadow_catcher: BoolProperty(
|
||||
name="Shadow Catcher",
|
||||
description="Pass containing shadows and light which is to be multiplied into backdrop",
|
||||
default=False,
|
||||
update=update_render_passes,
|
||||
)
|
||||
|
||||
use_denoising: BoolProperty(
|
||||
name="Use Denoising",
|
||||
description="Denoise the rendered image",
|
||||
default=True,
|
||||
update=update_render_passes,
|
||||
)
|
||||
denoising_diffuse_direct: BoolProperty(
|
||||
name="Diffuse Direct",
|
||||
description="Denoise the direct diffuse lighting",
|
||||
default=True,
|
||||
)
|
||||
denoising_diffuse_indirect: BoolProperty(
|
||||
name="Diffuse Indirect",
|
||||
description="Denoise the indirect diffuse lighting",
|
||||
default=True,
|
||||
)
|
||||
denoising_glossy_direct: BoolProperty(
|
||||
name="Glossy Direct",
|
||||
description="Denoise the direct glossy lighting",
|
||||
default=True,
|
||||
)
|
||||
denoising_glossy_indirect: BoolProperty(
|
||||
name="Glossy Indirect",
|
||||
description="Denoise the indirect glossy lighting",
|
||||
default=True,
|
||||
)
|
||||
denoising_transmission_direct: BoolProperty(
|
||||
name="Transmission Direct",
|
||||
description="Denoise the direct transmission lighting",
|
||||
default=True,
|
||||
)
|
||||
denoising_transmission_indirect: BoolProperty(
|
||||
name="Transmission Indirect",
|
||||
description="Denoise the indirect transmission lighting",
|
||||
default=True,
|
||||
)
|
||||
denoising_strength: FloatProperty(
|
||||
name="Denoising Strength",
|
||||
description="Controls neighbor pixel weighting for the denoising filter (lower values preserve more detail, but aren't as smooth)",
|
||||
min=0.0, max=1.0,
|
||||
default=0.5,
|
||||
)
|
||||
denoising_feature_strength: FloatProperty(
|
||||
name="Denoising Feature Strength",
|
||||
description="Controls removal of noisy image feature passes (lower values preserve more detail, but aren't as smooth)",
|
||||
min=0.0, max=1.0,
|
||||
default=0.5,
|
||||
)
|
||||
denoising_radius: IntProperty(
|
||||
name="Denoising Radius",
|
||||
description="Size of the image area that's used to denoise a pixel (higher values are smoother, but might lose detail and are slower)",
|
||||
min=1, max=25,
|
||||
default=8,
|
||||
subtype="PIXEL",
|
||||
)
|
||||
denoising_relative_pca: BoolProperty(
|
||||
name="Relative Filter",
|
||||
description="When removing pixels that don't carry information, use a relative threshold instead of an absolute one (can help to reduce artifacts, but might cause detail loss around edges)",
|
||||
default=False,
|
||||
)
|
||||
denoising_store_passes: BoolProperty(
|
||||
name="Store Denoising Passes",
|
||||
description="Store the denoising feature passes and the noisy image. The passes adapt to the denoiser selected for rendering",
|
||||
default=False,
|
||||
update=update_render_passes,
|
||||
)
|
||||
denoising_neighbor_frames: IntProperty(
|
||||
name="Neighbor Frames",
|
||||
description="Number of neighboring frames to use for denoising animations (more frames produce smoother results at the cost of performance)",
|
||||
min=0, max=7,
|
||||
default=0,
|
||||
)
|
||||
|
||||
denoising_optix_input_passes: EnumProperty(
|
||||
name="Input Passes",
|
||||
description="Passes used by the denoiser to distinguish noise from shader and geometry detail",
|
||||
items=enum_denoising_input_passes,
|
||||
default='RGB_ALBEDO',
|
||||
)
|
||||
denoising_openimagedenoise_input_passes: EnumProperty(
|
||||
name="Input Passes",
|
||||
description="Passes used by the denoiser to distinguish noise from shader and geometry detail",
|
||||
items=enum_denoising_input_passes,
|
||||
default='RGB_ALBEDO_NORMAL',
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def register(cls):
|
||||
@@ -1454,14 +1266,12 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
||||
|
||||
def get_device_types(self, context):
|
||||
import _cycles
|
||||
has_cuda, has_optix, has_opencl = _cycles.get_device_types()
|
||||
has_cuda, has_optix = _cycles.get_device_types()
|
||||
list = [('NONE', "None", "Don't use compute device", 0)]
|
||||
if has_cuda:
|
||||
list.append(('CUDA', "CUDA", "Use CUDA for GPU acceleration", 1))
|
||||
if has_optix:
|
||||
list.append(('OPTIX', "OptiX", "Use OptiX for GPU acceleration", 3))
|
||||
if has_opencl:
|
||||
list.append(('OPENCL', "OpenCL", "Use OpenCL for GPU acceleration", 2))
|
||||
return list
|
||||
|
||||
compute_device_type: EnumProperty(
|
||||
@@ -1486,7 +1296,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
||||
|
||||
def update_device_entries(self, device_list):
|
||||
for device in device_list:
|
||||
if not device[1] in {'CUDA', 'OPTIX', 'OPENCL', 'CPU'}:
|
||||
if not device[1] in {'CUDA', 'OPTIX', 'CPU'}:
|
||||
continue
|
||||
# Try to find existing Device entry
|
||||
entry = self.find_existing_device_entry(device)
|
||||
@@ -1520,22 +1330,23 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
||||
elif entry.type == 'CPU':
|
||||
cpu_devices.append(entry)
|
||||
# Extend all GPU devices with CPU.
|
||||
if compute_device_type in {'CUDA', 'OPTIX', 'OPENCL'}:
|
||||
if compute_device_type != 'CPU':
|
||||
devices.extend(cpu_devices)
|
||||
return devices
|
||||
|
||||
# For backwards compatibility, only returns CUDA and OpenCL but still
|
||||
# refreshes all devices.
|
||||
def get_devices(self, compute_device_type=''):
|
||||
# Refresh device list. This does not happen automatically on Blender
|
||||
# startup due to unstable OpenCL implementations that can cause crashes.
|
||||
def refresh_devices(self):
|
||||
import _cycles
|
||||
# Ensure `self.devices` is not re-allocated when the second call to
|
||||
# get_devices_for_type is made, freeing items from the first list.
|
||||
for device_type in ('CUDA', 'OPTIX', 'OPENCL'):
|
||||
self.update_device_entries(_cycles.available_devices(device_type))
|
||||
|
||||
cuda_devices = self.get_devices_for_type('CUDA')
|
||||
opencl_devices = self.get_devices_for_type('OPENCL')
|
||||
return cuda_devices, opencl_devices
|
||||
# Deprecated: use refresh_devices instead.
|
||||
def get_devices(self, compute_device_type=''):
|
||||
self.refresh_devices()
|
||||
return None
|
||||
|
||||
def get_num_gpu_devices(self):
|
||||
import _cycles
|
||||
@@ -1601,6 +1412,10 @@ class CyclesView3DShadingSettings(bpy.types.PropertyGroup):
|
||||
items=enum_view3d_shading_render_pass,
|
||||
default='COMBINED',
|
||||
)
|
||||
show_active_pixels: BoolProperty(
|
||||
name="Show Active Pixels",
|
||||
description="When using adaptive sampling highlight pixels which are being sampled",
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
|
@@ -34,6 +34,12 @@ class CYCLES_PT_sampling_presets(PresetPanel, Panel):
|
||||
preset_add_operator = "render.cycles_sampling_preset_add"
|
||||
COMPAT_ENGINES = {'CYCLES'}
|
||||
|
||||
class CYCLES_PT_viewport_sampling_presets(PresetPanel, Panel):
|
||||
bl_label = "Viewport Sampling Presets"
|
||||
preset_subdir = "cycles/viewport_sampling"
|
||||
preset_operator = "script.execute_preset"
|
||||
preset_add_operator = "render.cycles_viewport_sampling_preset_add"
|
||||
COMPAT_ENGINES = {'CYCLES'}
|
||||
|
||||
class CYCLES_PT_integrator_presets(PresetPanel, Panel):
|
||||
bl_label = "Integrator Presets"
|
||||
@@ -54,6 +60,15 @@ class CyclesButtonsPanel:
|
||||
return context.engine in cls.COMPAT_ENGINES
|
||||
|
||||
|
||||
class CyclesDebugButtonsPanel(CyclesButtonsPanel):
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
prefs = bpy.context.preferences
|
||||
return (CyclesButtonsPanel.poll(context)
|
||||
and prefs.experimental.use_cycles_debug
|
||||
and prefs.view.show_developer_ui)
|
||||
|
||||
|
||||
# Adapt properties editor panel to display in node editor. We have to
|
||||
# copy the class rather than inherit due to the way bpy registration works.
|
||||
def node_panel(cls):
|
||||
@@ -78,12 +93,6 @@ def use_cpu(context):
|
||||
return (get_device_type(context) == 'NONE' or cscene.device == 'CPU')
|
||||
|
||||
|
||||
def use_opencl(context):
|
||||
cscene = context.scene.cycles
|
||||
|
||||
return (get_device_type(context) == 'OPENCL' and cscene.device == 'GPU')
|
||||
|
||||
|
||||
def use_cuda(context):
|
||||
cscene = context.scene.cycles
|
||||
|
||||
@@ -96,12 +105,6 @@ def use_optix(context):
|
||||
return (get_device_type(context) == 'OPTIX' and cscene.device == 'GPU')
|
||||
|
||||
|
||||
def use_branched_path(context):
|
||||
cscene = context.scene.cycles
|
||||
|
||||
return (cscene.progressive == 'BRANCHED_PATH' and not use_optix(context))
|
||||
|
||||
|
||||
def use_sample_all_lights(context):
|
||||
cscene = context.scene.cycles
|
||||
|
||||
@@ -115,55 +118,93 @@ def show_device_active(context):
|
||||
return context.preferences.addons[__package__].preferences.has_active_device()
|
||||
|
||||
|
||||
def draw_samples_info(layout, context):
|
||||
cscene = context.scene.cycles
|
||||
integrator = cscene.progressive
|
||||
def get_effective_preview_denoiser(context):
|
||||
scene = context.scene
|
||||
cscene = scene.cycles
|
||||
|
||||
# Calculate sample values
|
||||
if integrator == 'PATH':
|
||||
aa = cscene.samples
|
||||
if cscene.use_square_samples:
|
||||
aa = aa * aa
|
||||
else:
|
||||
aa = cscene.aa_samples
|
||||
d = cscene.diffuse_samples
|
||||
g = cscene.glossy_samples
|
||||
t = cscene.transmission_samples
|
||||
ao = cscene.ao_samples
|
||||
ml = cscene.mesh_light_samples
|
||||
sss = cscene.subsurface_samples
|
||||
vol = cscene.volume_samples
|
||||
if cscene.preview_denoiser != "AUTO":
|
||||
return cscene.preview_denoiser
|
||||
|
||||
if cscene.use_square_samples:
|
||||
aa = aa * aa
|
||||
d = d * d
|
||||
g = g * g
|
||||
t = t * t
|
||||
ao = ao * ao
|
||||
ml = ml * ml
|
||||
sss = sss * sss
|
||||
vol = vol * vol
|
||||
if context.preferences.addons[__package__].preferences.get_devices_for_type('OPTIX'):
|
||||
return 'OPTIX'
|
||||
|
||||
return 'OIDN'
|
||||
|
||||
# Draw interface
|
||||
# Do not draw for progressive, when Square Samples are disabled
|
||||
if use_branched_path(context) or (cscene.use_square_samples and integrator == 'PATH'):
|
||||
col = layout.column(align=True)
|
||||
col.scale_y = 0.6
|
||||
col.label(text="Total Samples:")
|
||||
col.separator()
|
||||
if integrator == 'PATH':
|
||||
col.label(text="%s AA" % aa)
|
||||
else:
|
||||
col.label(text="%s AA, %s Diffuse, %s Glossy, %s Transmission" %
|
||||
(aa, d * aa, g * aa, t * aa))
|
||||
col.separator()
|
||||
col.label(text="%s AO, %s Mesh Light, %s Subsurface, %s Volume" %
|
||||
(ao * aa, ml * aa, sss * aa, vol * aa))
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Sampling"
|
||||
|
||||
def draw(self, context):
|
||||
pass
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_sampling_viewport(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Viewport"
|
||||
bl_parent_id = "CYCLES_RENDER_PT_sampling"
|
||||
|
||||
def draw_header_preset(self, context):
|
||||
CYCLES_PT_viewport_sampling_presets.draw_panel_header(self.layout)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
scene = context.scene
|
||||
cscene = scene.cycles
|
||||
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
heading = layout.column(align=True, heading="Noise Threshold")
|
||||
row = heading.row(align=True)
|
||||
row.prop(cscene, "use_preview_adaptive_sampling", text="")
|
||||
sub = row.row()
|
||||
sub.active = cscene.use_preview_adaptive_sampling
|
||||
sub.prop(cscene, "preview_adaptive_threshold", text="")
|
||||
|
||||
if cscene.use_preview_adaptive_sampling:
|
||||
col = layout.column(align=True)
|
||||
col.prop(cscene, "preview_samples", text=" Max Samples")
|
||||
col.prop(cscene, "preview_adaptive_min_samples", text="Min Samples")
|
||||
else:
|
||||
layout.prop(cscene, "preview_samples", text="Samples")
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_sampling_viewport_denoise(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Denoise"
|
||||
bl_parent_id = 'CYCLES_RENDER_PT_sampling_viewport'
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw_header(self, context):
|
||||
scene = context.scene
|
||||
cscene = scene.cycles
|
||||
|
||||
self.layout.prop(context.scene.cycles, "use_preview_denoising", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
scene = context.scene
|
||||
cscene = scene.cycles
|
||||
|
||||
col = layout.column()
|
||||
col.active = cscene.use_preview_denoising
|
||||
col.prop(cscene, "preview_denoiser", text="Denoiser")
|
||||
col.prop(cscene, "preview_denoising_input_passes", text="Passes")
|
||||
|
||||
effective_preview_denoiser = get_effective_preview_denoiser(context)
|
||||
if effective_preview_denoiser == 'OPENIMAGEDENOISE':
|
||||
col.prop(cscene, "preview_denoising_prefilter", text="Prefilter")
|
||||
|
||||
col.prop(cscene, "preview_denoising_start_sample", text="Start Sample")
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_sampling_render(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Render"
|
||||
bl_parent_id = "CYCLES_RENDER_PT_sampling"
|
||||
|
||||
def draw_header_preset(self, context):
|
||||
CYCLES_PT_sampling_presets.draw_panel_header(self.layout)
|
||||
|
||||
@@ -176,64 +217,32 @@ class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel):
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
if not use_optix(context):
|
||||
layout.prop(cscene, "progressive")
|
||||
|
||||
if not use_branched_path(context):
|
||||
col = layout.column(align=True)
|
||||
col.prop(cscene, "samples", text="Render")
|
||||
col.prop(cscene, "preview_samples", text="Viewport")
|
||||
else:
|
||||
col = layout.column(align=True)
|
||||
col.prop(cscene, "aa_samples", text="Render")
|
||||
col.prop(cscene, "preview_aa_samples", text="Viewport")
|
||||
|
||||
if not use_branched_path(context):
|
||||
draw_samples_info(layout, context)
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_sampling_sub_samples(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Sub Samples"
|
||||
bl_parent_id = "CYCLES_RENDER_PT_sampling"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return use_branched_path(context)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
scene = context.scene
|
||||
cscene = scene.cycles
|
||||
heading = layout.column(align=True, heading="Noise Threshold")
|
||||
row = heading.row(align=True)
|
||||
row.prop(cscene, "use_adaptive_sampling", text="")
|
||||
sub = row.row()
|
||||
sub.active = cscene.use_adaptive_sampling
|
||||
sub.prop(cscene, "adaptive_threshold", text="")
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(cscene, "diffuse_samples", text="Diffuse")
|
||||
col.prop(cscene, "glossy_samples", text="Glossy")
|
||||
col.prop(cscene, "transmission_samples", text="Transmission")
|
||||
col.prop(cscene, "ao_samples", text="AO")
|
||||
|
||||
sub = col.row(align=True)
|
||||
sub.active = use_sample_all_lights(context)
|
||||
sub.prop(cscene, "mesh_light_samples", text="Mesh Light")
|
||||
col.prop(cscene, "subsurface_samples", text="Subsurface")
|
||||
col.prop(cscene, "volume_samples", text="Volume")
|
||||
|
||||
draw_samples_info(layout, context)
|
||||
if cscene.use_adaptive_sampling:
|
||||
col.prop(cscene, "samples", text=" Max Samples")
|
||||
col.prop(cscene, "adaptive_min_samples", text="Min Samples")
|
||||
else:
|
||||
col.prop(cscene, "samples", text="Samples")
|
||||
col.prop(cscene, "time_limit")
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_sampling_adaptive(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Adaptive Sampling"
|
||||
bl_parent_id = "CYCLES_RENDER_PT_sampling"
|
||||
class CYCLES_RENDER_PT_sampling_render_denoise(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Denoise"
|
||||
bl_parent_id = 'CYCLES_RENDER_PT_sampling_render'
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw_header(self, context):
|
||||
layout = self.layout
|
||||
scene = context.scene
|
||||
cscene = scene.cycles
|
||||
|
||||
layout.prop(cscene, "use_adaptive_sampling", text="")
|
||||
self.layout.prop(context.scene.cycles, "use_denoising", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@@ -243,53 +252,12 @@ class CYCLES_RENDER_PT_sampling_adaptive(CyclesButtonsPanel, Panel):
|
||||
scene = context.scene
|
||||
cscene = scene.cycles
|
||||
|
||||
layout.active = cscene.use_adaptive_sampling
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(cscene, "adaptive_threshold", text="Noise Threshold")
|
||||
col.prop(cscene, "adaptive_min_samples", text="Min Samples")
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_sampling_denoising(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Denoising"
|
||||
bl_parent_id = "CYCLES_RENDER_PT_sampling"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
scene = context.scene
|
||||
cscene = scene.cycles
|
||||
|
||||
heading = layout.column(align=True, heading="Render")
|
||||
row = heading.row(align=True)
|
||||
row.prop(cscene, "use_denoising", text="")
|
||||
sub = row.row()
|
||||
|
||||
sub.active = cscene.use_denoising
|
||||
for view_layer in scene.view_layers:
|
||||
if view_layer.cycles.denoising_store_passes:
|
||||
sub.active = True
|
||||
|
||||
sub.prop(cscene, "denoiser", text="")
|
||||
|
||||
layout.separator()
|
||||
|
||||
heading = layout.column(align=False, heading="Viewport")
|
||||
row = heading.row(align=True)
|
||||
row.prop(cscene, "use_preview_denoising", text="")
|
||||
sub = row.row()
|
||||
sub.active = cscene.use_preview_denoising
|
||||
sub.prop(cscene, "preview_denoiser", text="")
|
||||
|
||||
sub = heading.row(align=True)
|
||||
sub.active = cscene.use_preview_denoising
|
||||
sub.prop(cscene, "preview_denoising_start_sample", text="Start Sample")
|
||||
sub = heading.row(align=True)
|
||||
sub.active = cscene.use_preview_denoising
|
||||
sub.prop(cscene, "preview_denoising_input_passes", text="Input Passes")
|
||||
col = layout.column()
|
||||
col.active = cscene.use_denoising
|
||||
col.prop(cscene, "denoiser", text="Denoiser")
|
||||
col.prop(cscene, "denoising_input_passes", text="Passes")
|
||||
if cscene.denoiser == 'OPENIMAGEDENOISE':
|
||||
col.prop(cscene, "denoising_prefilter", text="Prefilter")
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
|
||||
@@ -313,8 +281,6 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
|
||||
col.active = not(cscene.use_adaptive_sampling)
|
||||
col.prop(cscene, "sampling_pattern", text="Pattern")
|
||||
|
||||
layout.prop(cscene, "use_square_samples")
|
||||
|
||||
layout.separator()
|
||||
|
||||
col = layout.column(align=True)
|
||||
@@ -322,11 +288,6 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
|
||||
col.prop(cscene, "min_transparent_bounces")
|
||||
col.prop(cscene, "light_sampling_threshold", text="Light Threshold")
|
||||
|
||||
if cscene.progressive != 'PATH' and use_branched_path(context):
|
||||
col = layout.column(align=True)
|
||||
col.prop(cscene, "sample_all_lights_direct")
|
||||
col.prop(cscene, "sample_all_lights_indirect")
|
||||
|
||||
for view_layer in scene.view_layers:
|
||||
if view_layer.samples > 0:
|
||||
layout.separator()
|
||||
@@ -334,62 +295,6 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
|
||||
break
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_sampling_total(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Total Samples"
|
||||
bl_parent_id = "CYCLES_RENDER_PT_sampling"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
scene = context.scene
|
||||
cscene = scene.cycles
|
||||
|
||||
if cscene.use_square_samples:
|
||||
return True
|
||||
|
||||
return cscene.progressive != 'PATH' and use_branched_path(context)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
cscene = context.scene.cycles
|
||||
integrator = cscene.progressive
|
||||
|
||||
# Calculate sample values
|
||||
if integrator == 'PATH':
|
||||
aa = cscene.samples
|
||||
if cscene.use_square_samples:
|
||||
aa = aa * aa
|
||||
else:
|
||||
aa = cscene.aa_samples
|
||||
d = cscene.diffuse_samples
|
||||
g = cscene.glossy_samples
|
||||
t = cscene.transmission_samples
|
||||
ao = cscene.ao_samples
|
||||
ml = cscene.mesh_light_samples
|
||||
sss = cscene.subsurface_samples
|
||||
vol = cscene.volume_samples
|
||||
|
||||
if cscene.use_square_samples:
|
||||
aa = aa * aa
|
||||
d = d * d
|
||||
g = g * g
|
||||
t = t * t
|
||||
ao = ao * ao
|
||||
ml = ml * ml
|
||||
sss = sss * sss
|
||||
vol = vol * vol
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.scale_y = 0.6
|
||||
if integrator == 'PATH':
|
||||
col.label(text="%s AA" % aa)
|
||||
else:
|
||||
col.label(text="%s AA, %s Diffuse, %s Glossy, %s Transmission" %
|
||||
(aa, d * aa, g * aa, t * aa))
|
||||
col.separator()
|
||||
col.label(text="%s AO, %s Mesh Light, %s Subsurface, %s Volume" %
|
||||
(ao * aa, ml * aa, sss * aa, vol * aa))
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_subdivision(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Subdivision"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
@@ -548,6 +453,8 @@ class CYCLES_RENDER_PT_light_paths_fast_gi(CyclesButtonsPanel, Panel):
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
layout.active = cscene.use_fast_gi
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(cscene, "ao_bounces", text="Viewport Bounces")
|
||||
col.prop(cscene, "ao_bounces_render", text="Render Bounces")
|
||||
@@ -716,19 +623,13 @@ class CYCLES_RENDER_PT_performance_tiles(CyclesButtonsPanel, Panel):
|
||||
layout.use_property_decorate = False
|
||||
|
||||
scene = context.scene
|
||||
rd = scene.render
|
||||
cscene = scene.cycles
|
||||
|
||||
col = layout.column()
|
||||
|
||||
sub = col.column(align=True)
|
||||
sub.prop(rd, "tile_x", text="Tiles X")
|
||||
sub.prop(rd, "tile_y", text="Y")
|
||||
col.prop(cscene, "tile_order", text="Order")
|
||||
|
||||
col.prop(cscene, "use_auto_tile")
|
||||
sub = col.column()
|
||||
sub.active = not rd.use_save_buffers and not cscene.use_adaptive_sampling
|
||||
sub.prop(cscene, "use_progressive_refine")
|
||||
sub.active = cscene.use_auto_tile
|
||||
sub.prop(cscene, "tile_size")
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_performance_acceleration_structure(CyclesButtonsPanel, Panel):
|
||||
@@ -778,7 +679,6 @@ class CYCLES_RENDER_PT_performance_final_render(CyclesButtonsPanel, Panel):
|
||||
|
||||
col = layout.column()
|
||||
|
||||
col.prop(rd, "use_save_buffers")
|
||||
col.prop(rd, "use_persistent_data", text="Persistent Data")
|
||||
|
||||
|
||||
@@ -797,7 +697,6 @@ class CYCLES_RENDER_PT_performance_viewport(CyclesButtonsPanel, Panel):
|
||||
|
||||
col = layout.column()
|
||||
col.prop(rd, "preview_pixel_size", text="Pixel Size")
|
||||
col.prop(cscene, "preview_start_resolution", text="Start Pixels")
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
|
||||
@@ -818,7 +717,6 @@ class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
|
||||
|
||||
col = layout.column(heading="Include")
|
||||
col.prop(view_layer, "use_sky", text="Environment")
|
||||
col.prop(view_layer, "use_ao", text="Ambient Occlusion")
|
||||
col.prop(view_layer, "use_solid", text="Surfaces")
|
||||
col.prop(view_layer, "use_strand", text="Hair")
|
||||
col.prop(view_layer, "use_volumes", text="Volumes")
|
||||
@@ -827,6 +725,9 @@ class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
|
||||
sub = col.row()
|
||||
sub.prop(view_layer, "use_motion_blur", text="Motion Blur")
|
||||
sub.active = rd.use_motion_blur
|
||||
sub = col.row()
|
||||
sub.prop(view_layer.cycles, 'use_denoising', text='Denoising')
|
||||
sub.active = scene.cycles.use_denoising
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_override(CyclesButtonsPanel, Panel):
|
||||
@@ -872,6 +773,7 @@ class CYCLES_RENDER_PT_passes_data(CyclesButtonsPanel, Panel):
|
||||
col.prop(view_layer, "use_pass_combined")
|
||||
col.prop(view_layer, "use_pass_z")
|
||||
col.prop(view_layer, "use_pass_mist")
|
||||
col.prop(view_layer, "use_pass_position")
|
||||
col.prop(view_layer, "use_pass_normal")
|
||||
sub = col.column()
|
||||
sub.active = not rd.use_motion_blur
|
||||
@@ -928,6 +830,7 @@ class CYCLES_RENDER_PT_passes_light(CyclesButtonsPanel, Panel):
|
||||
col.prop(view_layer, "use_pass_environment")
|
||||
col.prop(view_layer, "use_pass_shadow")
|
||||
col.prop(view_layer, "use_pass_ambient_occlusion", text="Ambient Occlusion")
|
||||
col.prop(cycles_view_layer, "use_pass_shadow_catcher")
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_passes_crypto(CyclesButtonsPanel, ViewLayerCryptomattePanel, Panel):
|
||||
@@ -942,70 +845,6 @@ class CYCLES_RENDER_PT_passes_aov(CyclesButtonsPanel, ViewLayerAOVPanel):
|
||||
bl_parent_id = "CYCLES_RENDER_PT_passes"
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Denoising"
|
||||
bl_context = "view_layer"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
cscene = context.scene.cycles
|
||||
return CyclesButtonsPanel.poll(context) and cscene.use_denoising
|
||||
|
||||
def draw_header(self, context):
|
||||
scene = context.scene
|
||||
view_layer = context.view_layer
|
||||
cycles_view_layer = view_layer.cycles
|
||||
|
||||
layout = self.layout
|
||||
layout.prop(cycles_view_layer, "use_denoising", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
scene = context.scene
|
||||
view_layer = context.view_layer
|
||||
cycles_view_layer = view_layer.cycles
|
||||
denoiser = scene.cycles.denoiser
|
||||
|
||||
layout.active = denoiser != 'NONE' and cycles_view_layer.use_denoising
|
||||
|
||||
col = layout.column()
|
||||
|
||||
if denoiser == 'OPTIX':
|
||||
col.prop(cycles_view_layer, "denoising_optix_input_passes")
|
||||
return
|
||||
elif denoiser == 'OPENIMAGEDENOISE':
|
||||
col.prop(cycles_view_layer, "denoising_openimagedenoise_input_passes")
|
||||
return
|
||||
|
||||
col.prop(cycles_view_layer, "denoising_radius", text="Radius")
|
||||
|
||||
col = layout.column()
|
||||
col.prop(cycles_view_layer, "denoising_strength", slider=True, text="Strength")
|
||||
col.prop(cycles_view_layer, "denoising_feature_strength", slider=True, text="Feature Strength")
|
||||
col.prop(cycles_view_layer, "denoising_relative_pca")
|
||||
|
||||
layout.separator()
|
||||
|
||||
col = layout.column()
|
||||
col.active = cycles_view_layer.use_denoising or cycles_view_layer.denoising_store_passes
|
||||
|
||||
row = col.row(heading="Diffuse", align=True)
|
||||
row.prop(cycles_view_layer, "denoising_diffuse_direct", text="Direct", toggle=True)
|
||||
row.prop(cycles_view_layer, "denoising_diffuse_indirect", text="Indirect", toggle=True)
|
||||
|
||||
row = col.row(heading="Glossy", align=True)
|
||||
row.prop(cycles_view_layer, "denoising_glossy_direct", text="Direct", toggle=True)
|
||||
row.prop(cycles_view_layer, "denoising_glossy_indirect", text="Indirect", toggle=True)
|
||||
|
||||
row = col.row(heading="Transmission", align=True)
|
||||
row.prop(cycles_view_layer, "denoising_transmission_direct", text="Direct", toggle=True)
|
||||
row.prop(cycles_view_layer, "denoising_transmission_indirect", text="Indirect", toggle=True)
|
||||
|
||||
|
||||
class CYCLES_PT_post_processing(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Post Processing"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
@@ -1417,10 +1256,6 @@ class CYCLES_LIGHT_PT_light(CyclesButtonsPanel, Panel):
|
||||
|
||||
if not (light.type == 'AREA' and clamp.is_portal):
|
||||
sub = col.column()
|
||||
if use_branched_path(context):
|
||||
subsub = sub.row(align=True)
|
||||
subsub.active = use_sample_all_lights(context)
|
||||
subsub.prop(clamp, "samples")
|
||||
sub.prop(clamp, "max_bounces")
|
||||
|
||||
sub = col.column(align=True)
|
||||
@@ -1526,34 +1361,6 @@ class CYCLES_WORLD_PT_volume(CyclesButtonsPanel, Panel):
|
||||
panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume')
|
||||
|
||||
|
||||
class CYCLES_WORLD_PT_ambient_occlusion(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Ambient Occlusion"
|
||||
bl_context = "world"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.world and CyclesButtonsPanel.poll(context)
|
||||
|
||||
def draw_header(self, context):
|
||||
light = context.world.light_settings
|
||||
self.layout.prop(light, "use_ambient_occlusion", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
light = context.world.light_settings
|
||||
scene = context.scene
|
||||
|
||||
col = layout.column()
|
||||
sub = col.column()
|
||||
sub.active = light.use_ambient_occlusion or scene.render.use_simplify
|
||||
sub.prop(light, "ao_factor", text="Factor")
|
||||
col.prop(light, "distance", text="Distance")
|
||||
|
||||
|
||||
class CYCLES_WORLD_PT_mist(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Mist Pass"
|
||||
bl_context = "world"
|
||||
@@ -1650,10 +1457,6 @@ class CYCLES_WORLD_PT_settings_surface(CyclesButtonsPanel, Panel):
|
||||
subsub = sub.row(align=True)
|
||||
subsub.active = cworld.sampling_method == 'MANUAL'
|
||||
subsub.prop(cworld, "sample_map_resolution")
|
||||
if use_branched_path(context):
|
||||
subsub = sub.column(align=True)
|
||||
subsub.active = use_sample_all_lights(context)
|
||||
subsub.prop(cworld, "samples")
|
||||
sub.prop(cworld, "max_bounces")
|
||||
|
||||
|
||||
@@ -1677,8 +1480,7 @@ class CYCLES_WORLD_PT_settings_volume(CyclesButtonsPanel, Panel):
|
||||
col = layout.column()
|
||||
|
||||
sub = col.column()
|
||||
sub.active = use_cpu(context)
|
||||
sub.prop(cworld, "volume_sampling", text="Sampling")
|
||||
col.prop(cworld, "volume_sampling", text="Sampling")
|
||||
col.prop(cworld, "volume_interpolation", text="Interpolation")
|
||||
col.prop(cworld, "homogeneous_volume", text="Homogeneous")
|
||||
sub = col.column()
|
||||
@@ -1817,8 +1619,7 @@ class CYCLES_MATERIAL_PT_settings_volume(CyclesButtonsPanel, Panel):
|
||||
|
||||
col = layout.column()
|
||||
sub = col.column()
|
||||
sub.active = use_cpu(context)
|
||||
sub.prop(cmat, "volume_sampling", text="Sampling")
|
||||
col.prop(cmat, "volume_sampling", text="Sampling")
|
||||
col.prop(cmat, "volume_interpolation", text="Interpolation")
|
||||
col.prop(cmat, "homogeneous_volume", text="Homogeneous")
|
||||
sub = col.column()
|
||||
@@ -1845,9 +1646,6 @@ class CYCLES_RENDER_PT_bake(CyclesButtonsPanel, Panel):
|
||||
cbk = scene.render.bake
|
||||
rd = scene.render
|
||||
|
||||
if use_optix(context):
|
||||
layout.label(text="Baking is performed using CUDA instead of OptiX", icon='INFO')
|
||||
|
||||
if rd.use_bake_multires:
|
||||
layout.operator("object.bake_image", icon='RENDER_STILL')
|
||||
layout.prop(rd, "use_bake_multires")
|
||||
@@ -1905,7 +1703,6 @@ class CYCLES_RENDER_PT_bake_influence(CyclesButtonsPanel, Panel):
|
||||
col.prop(cbk, "use_pass_diffuse")
|
||||
col.prop(cbk, "use_pass_glossy")
|
||||
col.prop(cbk, "use_pass_transmission")
|
||||
col.prop(cbk, "use_pass_ambient_occlusion")
|
||||
col.prop(cbk, "use_pass_emit")
|
||||
|
||||
elif cscene.bake_type in {'DIFFUSE', 'GLOSSY', 'TRANSMISSION'}:
|
||||
@@ -1989,19 +1786,12 @@ class CYCLES_RENDER_PT_bake_output(CyclesButtonsPanel, Panel):
|
||||
layout.prop(cbk, "use_clear", text="Clear Image")
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel):
|
||||
class CYCLES_RENDER_PT_debug(CyclesDebugButtonsPanel, Panel):
|
||||
bl_label = "Debug"
|
||||
bl_context = "render"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {'CYCLES'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
prefs = bpy.context.preferences
|
||||
return (CyclesButtonsPanel.poll(context)
|
||||
and prefs.experimental.use_cycles_debug
|
||||
and prefs.view.show_developer_ui)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
@@ -2018,29 +1808,18 @@ class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel):
|
||||
row.prop(cscene, "debug_use_cpu_avx", toggle=True)
|
||||
row.prop(cscene, "debug_use_cpu_avx2", toggle=True)
|
||||
col.prop(cscene, "debug_bvh_layout")
|
||||
col.prop(cscene, "debug_use_cpu_split_kernel")
|
||||
|
||||
col.separator()
|
||||
|
||||
col = layout.column()
|
||||
col.label(text="CUDA Flags:")
|
||||
col.prop(cscene, "debug_use_cuda_adaptive_compile")
|
||||
col.prop(cscene, "debug_use_cuda_split_kernel")
|
||||
|
||||
col.separator()
|
||||
|
||||
col = layout.column()
|
||||
col.label(text="OptiX Flags:")
|
||||
col.prop(cscene, "debug_optix_cuda_streams")
|
||||
col.prop(cscene, "debug_optix_curves_api")
|
||||
|
||||
col.separator()
|
||||
|
||||
col = layout.column()
|
||||
col.label(text="OpenCL Flags:")
|
||||
col.prop(cscene, "debug_opencl_device_type", text="Device")
|
||||
col.prop(cscene, "debug_use_opencl_debug", text="Debug")
|
||||
col.prop(cscene, "debug_opencl_mem_limit")
|
||||
col.prop(cscene, "debug_use_optix_debug")
|
||||
|
||||
col.separator()
|
||||
|
||||
@@ -2141,20 +1920,22 @@ class CYCLES_RENDER_PT_simplify_culling(CyclesButtonsPanel, Panel):
|
||||
sub.prop(cscene, "distance_cull_margin", text="")
|
||||
|
||||
|
||||
class CYCLES_VIEW3D_PT_shading_render_pass(Panel):
|
||||
class CyclesShadingButtonsPanel(CyclesButtonsPanel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'HEADER'
|
||||
bl_label = "Render Pass"
|
||||
bl_parent_id = 'VIEW3D_PT_shading'
|
||||
COMPAT_ENGINES = {'CYCLES'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (
|
||||
context.engine in cls.COMPAT_ENGINES and
|
||||
CyclesButtonsPanel.poll(context) and
|
||||
context.space_data.shading.type == 'RENDERED'
|
||||
)
|
||||
|
||||
|
||||
class CYCLES_VIEW3D_PT_shading_render_pass(CyclesShadingButtonsPanel, Panel):
|
||||
bl_label = "Render Pass"
|
||||
|
||||
def draw(self, context):
|
||||
shading = context.space_data.shading
|
||||
|
||||
@@ -2162,6 +1943,26 @@ class CYCLES_VIEW3D_PT_shading_render_pass(Panel):
|
||||
layout.prop(shading.cycles, "render_pass", text="")
|
||||
|
||||
|
||||
class CYCLES_VIEW3D_PT_shading_debug(CyclesDebugButtonsPanel,
|
||||
CyclesShadingButtonsPanel,
|
||||
Panel):
|
||||
bl_label = "Debug"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (
|
||||
CyclesDebugButtonsPanel.poll(context) and
|
||||
CyclesShadingButtonsPanel.poll(context)
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
shading = context.space_data.shading
|
||||
|
||||
layout = self.layout
|
||||
layout.active = context.scene.cycles.use_preview_adaptive_sampling
|
||||
layout.prop(shading.cycles, "show_active_pixels")
|
||||
|
||||
|
||||
class CYCLES_VIEW3D_PT_shading_lighting(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'HEADER'
|
||||
@@ -2275,11 +2076,13 @@ def get_panels():
|
||||
|
||||
classes = (
|
||||
CYCLES_PT_sampling_presets,
|
||||
CYCLES_PT_viewport_sampling_presets,
|
||||
CYCLES_PT_integrator_presets,
|
||||
CYCLES_RENDER_PT_sampling,
|
||||
CYCLES_RENDER_PT_sampling_sub_samples,
|
||||
CYCLES_RENDER_PT_sampling_adaptive,
|
||||
CYCLES_RENDER_PT_sampling_denoising,
|
||||
CYCLES_RENDER_PT_sampling_viewport,
|
||||
CYCLES_RENDER_PT_sampling_viewport_denoise,
|
||||
CYCLES_RENDER_PT_sampling_render,
|
||||
CYCLES_RENDER_PT_sampling_render_denoise,
|
||||
CYCLES_RENDER_PT_sampling_advanced,
|
||||
CYCLES_RENDER_PT_light_paths,
|
||||
CYCLES_RENDER_PT_light_paths_max_bounces,
|
||||
@@ -2296,6 +2099,7 @@ classes = (
|
||||
CYCLES_VIEW3D_PT_simplify_greasepencil,
|
||||
CYCLES_VIEW3D_PT_shading_lighting,
|
||||
CYCLES_VIEW3D_PT_shading_render_pass,
|
||||
CYCLES_VIEW3D_PT_shading_debug,
|
||||
CYCLES_RENDER_PT_motion_blur,
|
||||
CYCLES_RENDER_PT_motion_blur_curve,
|
||||
CYCLES_RENDER_PT_film,
|
||||
@@ -2314,7 +2118,6 @@ classes = (
|
||||
CYCLES_RENDER_PT_passes_aov,
|
||||
CYCLES_RENDER_PT_filter,
|
||||
CYCLES_RENDER_PT_override,
|
||||
CYCLES_RENDER_PT_denoising,
|
||||
CYCLES_PT_post_processing,
|
||||
CYCLES_CAMERA_PT_dof,
|
||||
CYCLES_CAMERA_PT_dof_aperture,
|
||||
@@ -2333,7 +2136,6 @@ classes = (
|
||||
CYCLES_WORLD_PT_preview,
|
||||
CYCLES_WORLD_PT_surface,
|
||||
CYCLES_WORLD_PT_volume,
|
||||
CYCLES_WORLD_PT_ambient_occlusion,
|
||||
CYCLES_WORLD_PT_mist,
|
||||
CYCLES_WORLD_PT_ray_visibility,
|
||||
CYCLES_WORLD_PT_settings,
|
||||
|
@@ -109,7 +109,7 @@ def do_versions(self):
|
||||
library_versions.setdefault(library.version, []).append(library)
|
||||
|
||||
# Do versioning per library, since they might have different versions.
|
||||
max_need_versioning = (2, 93, 7)
|
||||
max_need_versioning = (3, 0, 25)
|
||||
for version, libraries in library_versions.items():
|
||||
if version > max_need_versioning:
|
||||
continue
|
||||
@@ -166,10 +166,6 @@ def do_versions(self):
|
||||
if not cscene.is_property_set("filter_type"):
|
||||
cscene.pixel_filter_type = 'GAUSSIAN'
|
||||
|
||||
# Tile Order
|
||||
if not cscene.is_property_set("tile_order"):
|
||||
cscene.tile_order = 'CENTER'
|
||||
|
||||
if version <= (2, 76, 10):
|
||||
cscene = scene.cycles
|
||||
if cscene.is_property_set("filter_type"):
|
||||
@@ -186,10 +182,6 @@ def do_versions(self):
|
||||
if version <= (2, 79, 0):
|
||||
cscene = scene.cycles
|
||||
# Default changes
|
||||
if not cscene.is_property_set("aa_samples"):
|
||||
cscene.aa_samples = 4
|
||||
if not cscene.is_property_set("preview_aa_samples"):
|
||||
cscene.preview_aa_samples = 4
|
||||
if not cscene.is_property_set("blur_glossy"):
|
||||
cscene.blur_glossy = 0.0
|
||||
if not cscene.is_property_set("sample_clamp_indirect"):
|
||||
@@ -203,7 +195,6 @@ def do_versions(self):
|
||||
view_layer.use_pass_cryptomatte_material = cview_layer.get("use_pass_crypto_material", False)
|
||||
view_layer.use_pass_cryptomatte_asset = cview_layer.get("use_pass_crypto_asset", False)
|
||||
view_layer.pass_cryptomatte_depth = cview_layer.get("pass_crypto_depth", 6)
|
||||
view_layer.use_pass_cryptomatte_accurate = cview_layer.get("pass_crypto_accurate", True)
|
||||
|
||||
if version <= (2, 93, 7):
|
||||
if scene.render.engine == 'CYCLES':
|
||||
@@ -229,6 +220,35 @@ def do_versions(self):
|
||||
cscene.ao_bounces = 1
|
||||
cscene.ao_bounces_render = 1
|
||||
|
||||
if version <= (3, 0, 25):
|
||||
cscene = scene.cycles
|
||||
|
||||
# Default changes.
|
||||
if not cscene.is_property_set("samples"):
|
||||
cscene.samples = 128
|
||||
if not cscene.is_property_set("preview_samples"):
|
||||
cscene.preview_samples = 32
|
||||
if not cscene.is_property_set("use_adaptive_sampling"):
|
||||
cscene.use_adaptive_sampling = False
|
||||
cscene.use_preview_adaptive_sampling = False
|
||||
if not cscene.is_property_set("use_denoising"):
|
||||
cscene.use_denoising = False
|
||||
if not cscene.is_property_set("use_preview_denoising"):
|
||||
cscene.use_preview_denoising = False
|
||||
if not cscene.is_property_set("sampling_pattern"):
|
||||
cscene.sampling_pattern = 'PROGRESSIVE_MUTI_JITTER'
|
||||
|
||||
# Removal of square samples.
|
||||
cscene = scene.cycles
|
||||
use_square_samples = cscene.get("use_square_samples", False)
|
||||
|
||||
if use_square_samples:
|
||||
cscene.samples *= cscene.samples
|
||||
cscene.preview_samples *= cscene.preview_samples
|
||||
for layer in scene.view_layers:
|
||||
layer.samples *= layer.samples
|
||||
cscene["use_square_samples"] = False
|
||||
|
||||
# Lamps
|
||||
for light in bpy.data.lights:
|
||||
if light.library not in libraries:
|
||||
@@ -249,10 +269,6 @@ def do_versions(self):
|
||||
if version <= (2, 76, 9):
|
||||
cworld = world.cycles
|
||||
|
||||
# World MIS Samples
|
||||
if not cworld.is_property_set("samples"):
|
||||
cworld.samples = 4
|
||||
|
||||
# World MIS Resolution
|
||||
if not cworld.is_property_set("sample_map_resolution"):
|
||||
cworld.sample_map_resolution = 256
|
||||
|
@@ -894,12 +894,8 @@ void BlenderSync::sync_view(BL::SpaceView3D &b_v3d,
|
||||
}
|
||||
}
|
||||
|
||||
BufferParams BlenderSync::get_buffer_params(BL::SpaceView3D &b_v3d,
|
||||
BL::RegionView3D &b_rv3d,
|
||||
Camera *cam,
|
||||
int width,
|
||||
int height,
|
||||
const bool use_denoiser)
|
||||
BufferParams BlenderSync::get_buffer_params(
|
||||
BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, int height)
|
||||
{
|
||||
BufferParams params;
|
||||
bool use_border = false;
|
||||
@@ -931,11 +927,6 @@ BufferParams BlenderSync::get_buffer_params(BL::SpaceView3D &b_v3d,
|
||||
params.height = height;
|
||||
}
|
||||
|
||||
PassType display_pass = update_viewport_display_passes(b_v3d, params.passes);
|
||||
|
||||
/* Can only denoise the combined image pass */
|
||||
params.denoising_data_pass = display_pass == PASS_COMBINED && use_denoiser;
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
|
@@ -526,8 +526,13 @@ bool BlenderSync::object_has_particle_hair(BL::Object b_ob)
|
||||
|
||||
/* Old particle hair. */
|
||||
void BlenderSync::sync_particle_hair(
|
||||
Hair *hair, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step)
|
||||
Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step)
|
||||
{
|
||||
if (!b_ob_info.is_real_object_data()) {
|
||||
return;
|
||||
}
|
||||
BL::Object b_ob = b_ob_info.real_object;
|
||||
|
||||
/* obtain general settings */
|
||||
if (b_ob.mode() == b_ob.mode_PARTICLE_EDIT || b_ob.mode() == b_ob.mode_EDIT) {
|
||||
return;
|
||||
@@ -788,10 +793,10 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st
|
||||
}
|
||||
|
||||
/* Hair object. */
|
||||
void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step)
|
||||
void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step)
|
||||
{
|
||||
/* Convert Blender hair to Cycles curves. */
|
||||
BL::Hair b_hair(b_ob.data());
|
||||
BL::Hair b_hair(b_ob_info.object_data);
|
||||
if (motion) {
|
||||
export_hair_curves_motion(hair, b_hair, motion_step);
|
||||
}
|
||||
@@ -800,16 +805,16 @@ void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motio
|
||||
}
|
||||
}
|
||||
#else
|
||||
void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step)
|
||||
void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step)
|
||||
{
|
||||
(void)hair;
|
||||
(void)b_ob;
|
||||
(void)b_ob_info;
|
||||
(void)motion;
|
||||
(void)motion_step;
|
||||
}
|
||||
#endif
|
||||
|
||||
void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair)
|
||||
void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Hair *hair)
|
||||
{
|
||||
/* make a copy of the shaders as the caller in the main thread still need them for syncing the
|
||||
* attributes */
|
||||
@@ -819,19 +824,19 @@ void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *ha
|
||||
new_hair.set_used_shaders(used_shaders);
|
||||
|
||||
if (view_layer.use_hair) {
|
||||
if (b_ob.type() == BL::Object::type_HAIR) {
|
||||
if (b_ob_info.object_data.is_a(&RNA_Hair)) {
|
||||
/* Hair object. */
|
||||
sync_hair(&new_hair, b_ob, false);
|
||||
sync_hair(&new_hair, b_ob_info, false);
|
||||
}
|
||||
else {
|
||||
/* Particle hair. */
|
||||
bool need_undeformed = new_hair.need_attribute(scene, ATTR_STD_GENERATED);
|
||||
BL::Mesh b_mesh = object_to_mesh(
|
||||
b_data, b_ob, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE);
|
||||
b_data, b_ob_info, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE);
|
||||
|
||||
if (b_mesh) {
|
||||
sync_particle_hair(&new_hair, b_mesh, b_ob, false);
|
||||
free_object_to_mesh(b_data, b_ob, b_mesh);
|
||||
sync_particle_hair(&new_hair, b_mesh, b_ob_info, false);
|
||||
free_object_to_mesh(b_data, b_ob_info, b_mesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -859,7 +864,7 @@ void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *ha
|
||||
}
|
||||
|
||||
void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph,
|
||||
BL::Object b_ob,
|
||||
BObjectInfo &b_ob_info,
|
||||
Hair *hair,
|
||||
int motion_step)
|
||||
{
|
||||
@@ -869,18 +874,19 @@ void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph,
|
||||
}
|
||||
|
||||
/* Export deformed coordinates. */
|
||||
if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
|
||||
if (b_ob.type() == BL::Object::type_HAIR) {
|
||||
if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
|
||||
if (b_ob_info.object_data.is_a(&RNA_Hair)) {
|
||||
/* Hair object. */
|
||||
sync_hair(hair, b_ob, true, motion_step);
|
||||
sync_hair(hair, b_ob_info, true, motion_step);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
/* Particle hair. */
|
||||
BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
|
||||
BL::Mesh b_mesh = object_to_mesh(
|
||||
b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
|
||||
if (b_mesh) {
|
||||
sync_particle_hair(hair, b_mesh, b_ob, true, motion_step);
|
||||
free_object_to_mesh(b_data, b_ob, b_mesh);
|
||||
sync_particle_hair(hair, b_mesh, b_ob_info, true, motion_step);
|
||||
free_object_to_mesh(b_data, b_ob_info, b_mesh);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@@ -25,7 +25,6 @@ CCL_NAMESPACE_BEGIN
|
||||
enum ComputeDevice {
|
||||
COMPUTE_DEVICE_CPU = 0,
|
||||
COMPUTE_DEVICE_CUDA = 1,
|
||||
COMPUTE_DEVICE_OPENCL = 2,
|
||||
COMPUTE_DEVICE_OPTIX = 3,
|
||||
|
||||
COMPUTE_DEVICE_NUM
|
||||
@@ -68,13 +67,6 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
|
||||
device = Device::get_multi_device(devices, threads, background);
|
||||
}
|
||||
}
|
||||
else if (get_enum(cscene, "device") == 2) {
|
||||
/* Find network device. */
|
||||
vector<DeviceInfo> devices = Device::available_devices(DEVICE_MASK_NETWORK);
|
||||
if (!devices.empty()) {
|
||||
device = devices.front();
|
||||
}
|
||||
}
|
||||
else if (get_enum(cscene, "device") == 1) {
|
||||
/* Test if we are using GPU devices. */
|
||||
ComputeDevice compute_device = (ComputeDevice)get_enum(
|
||||
@@ -89,9 +81,6 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
|
||||
else if (compute_device == COMPUTE_DEVICE_OPTIX) {
|
||||
mask |= DEVICE_MASK_OPTIX;
|
||||
}
|
||||
else if (compute_device == COMPUTE_DEVICE_OPENCL) {
|
||||
mask |= DEVICE_MASK_OPENCL;
|
||||
}
|
||||
vector<DeviceInfo> devices = Device::available_devices(mask);
|
||||
|
||||
/* Match device preferences and available devices. */
|
||||
|
@@ -29,13 +29,15 @@
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
static Geometry::Type determine_geom_type(BL::Object &b_ob, bool use_particle_hair)
|
||||
static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_particle_hair)
|
||||
{
|
||||
if (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) {
|
||||
if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) {
|
||||
return Geometry::HAIR;
|
||||
}
|
||||
|
||||
if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) {
|
||||
if (b_ob_info.object_data.is_a(&RNA_Volume) ||
|
||||
(b_ob_info.object_data == b_ob_info.real_object.data() &&
|
||||
object_fluid_gas_domain_find(b_ob_info.real_object))) {
|
||||
return Geometry::VOLUME;
|
||||
}
|
||||
|
||||
@@ -71,20 +73,17 @@ array<Node *> BlenderSync::find_used_shaders(BL::Object &b_ob)
|
||||
}
|
||||
|
||||
Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
BL::Object &b_ob,
|
||||
BL::Object &b_ob_instance,
|
||||
BObjectInfo &b_ob_info,
|
||||
bool object_updated,
|
||||
bool use_particle_hair,
|
||||
TaskPool *task_pool)
|
||||
{
|
||||
/* Test if we can instance or if the object is modified. */
|
||||
BL::ID b_ob_data = b_ob.data();
|
||||
BL::ID b_key_id = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data;
|
||||
Geometry::Type geom_type = determine_geom_type(b_ob, use_particle_hair);
|
||||
GeometryKey key(b_key_id.ptr.data, geom_type);
|
||||
Geometry::Type geom_type = determine_geom_type(b_ob_info, use_particle_hair);
|
||||
GeometryKey key(b_ob_info.object_data, geom_type);
|
||||
|
||||
/* Find shader indices. */
|
||||
array<Node *> used_shaders = find_used_shaders(b_ob);
|
||||
array<Node *> used_shaders = find_used_shaders(b_ob_info.iter_object);
|
||||
|
||||
/* Ensure we only sync instanced geometry once. */
|
||||
Geometry *geom = geometry_map.find(key);
|
||||
@@ -111,7 +110,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
}
|
||||
else {
|
||||
/* Test if we need to update existing geometry. */
|
||||
sync = geometry_map.update(geom, b_key_id);
|
||||
sync = geometry_map.update(geom, b_ob_info.object_data);
|
||||
}
|
||||
|
||||
if (!sync) {
|
||||
@@ -144,7 +143,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
|
||||
geometry_synced.insert(geom);
|
||||
|
||||
geom->name = ustring(b_ob_data.name().c_str());
|
||||
geom->name = ustring(b_ob_info.object_data.name().c_str());
|
||||
|
||||
/* Store the shaders immediately for the object attribute code. */
|
||||
geom->set_used_shaders(used_shaders);
|
||||
@@ -153,19 +152,19 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
|
||||
progress.set_sync_status("Synchronizing object", b_ob.name());
|
||||
progress.set_sync_status("Synchronizing object", b_ob_info.real_object.name());
|
||||
|
||||
if (geom_type == Geometry::HAIR) {
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
sync_hair(b_depsgraph, b_ob, hair);
|
||||
sync_hair(b_depsgraph, b_ob_info, hair);
|
||||
}
|
||||
else if (geom_type == Geometry::VOLUME) {
|
||||
Volume *volume = static_cast<Volume *>(geom);
|
||||
sync_volume(b_ob, volume);
|
||||
sync_volume(b_ob_info, volume);
|
||||
}
|
||||
else {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
sync_mesh(b_depsgraph, b_ob, mesh);
|
||||
sync_mesh(b_depsgraph, b_ob_info, mesh);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -181,7 +180,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
}
|
||||
|
||||
void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
|
||||
BL::Object &b_ob,
|
||||
BObjectInfo &b_ob_info,
|
||||
Object *object,
|
||||
float motion_time,
|
||||
bool use_particle_hair,
|
||||
@@ -190,8 +189,10 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
|
||||
/* Ensure we only sync instanced geometry once. */
|
||||
Geometry *geom = object->get_geometry();
|
||||
|
||||
if (geometry_motion_synced.find(geom) != geometry_motion_synced.end())
|
||||
if (geometry_motion_synced.find(geom) != geometry_motion_synced.end() ||
|
||||
geometry_motion_attribute_synced.find(geom) != geometry_motion_attribute_synced.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
geometry_motion_synced.insert(geom);
|
||||
|
||||
@@ -210,16 +211,17 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
|
||||
if (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) {
|
||||
if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) {
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
sync_hair_motion(b_depsgraph, b_ob, hair, motion_step);
|
||||
sync_hair_motion(b_depsgraph, b_ob_info, hair, motion_step);
|
||||
}
|
||||
else if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) {
|
||||
else if (b_ob_info.object_data.is_a(&RNA_Volume) ||
|
||||
object_fluid_gas_domain_find(b_ob_info.real_object)) {
|
||||
/* No volume motion blur support yet. */
|
||||
}
|
||||
else {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
sync_mesh_motion(b_depsgraph, b_ob, mesh, motion_step);
|
||||
sync_mesh_motion(b_depsgraph, b_ob_info, mesh, motion_step);
|
||||
}
|
||||
};
|
||||
|
||||
|
787
intern/cycles/blender/blender_gpu_display.cpp
Normal file
787
intern/cycles/blender/blender_gpu_display.cpp
Normal file
@@ -0,0 +1,787 @@
|
||||
/*
|
||||
* Copyright 2021 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "blender/blender_gpu_display.h"
|
||||
|
||||
#include "device/device.h"
|
||||
#include "util/util_logging.h"
|
||||
#include "util/util_opengl.h"
|
||||
|
||||
extern "C" {
|
||||
struct RenderEngine;
|
||||
|
||||
bool RE_engine_has_render_context(struct RenderEngine *engine);
|
||||
void RE_engine_render_context_enable(struct RenderEngine *engine);
|
||||
void RE_engine_render_context_disable(struct RenderEngine *engine);
|
||||
|
||||
bool DRW_opengl_context_release();
|
||||
void DRW_opengl_context_activate(bool drw_state);
|
||||
|
||||
void *WM_opengl_context_create();
|
||||
void WM_opengl_context_activate(void *gl_context);
|
||||
void WM_opengl_context_dispose(void *gl_context);
|
||||
void WM_opengl_context_release(void *context);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* BlenderDisplayShader.
|
||||
*/
|
||||
|
||||
unique_ptr<BlenderDisplayShader> BlenderDisplayShader::create(BL::RenderEngine &b_engine,
|
||||
BL::Scene &b_scene)
|
||||
{
|
||||
if (b_engine.support_display_space_shader(b_scene)) {
|
||||
return make_unique<BlenderDisplaySpaceShader>(b_engine, b_scene);
|
||||
}
|
||||
|
||||
return make_unique<BlenderFallbackDisplayShader>();
|
||||
}
|
||||
|
||||
int BlenderDisplayShader::get_position_attrib_location()
|
||||
{
|
||||
if (position_attribute_location_ == -1) {
|
||||
const uint shader_program = get_shader_program();
|
||||
position_attribute_location_ = glGetAttribLocation(shader_program, position_attribute_name);
|
||||
}
|
||||
return position_attribute_location_;
|
||||
}
|
||||
|
||||
int BlenderDisplayShader::get_tex_coord_attrib_location()
|
||||
{
|
||||
if (tex_coord_attribute_location_ == -1) {
|
||||
const uint shader_program = get_shader_program();
|
||||
tex_coord_attribute_location_ = glGetAttribLocation(shader_program, tex_coord_attribute_name);
|
||||
}
|
||||
return tex_coord_attribute_location_;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* BlenderFallbackDisplayShader.
|
||||
*/
|
||||
|
||||
/* TODO move shaders to standalone .glsl file. */
|
||||
static const char *FALLBACK_VERTEX_SHADER =
|
||||
"#version 330\n"
|
||||
"uniform vec2 fullscreen;\n"
|
||||
"in vec2 texCoord;\n"
|
||||
"in vec2 pos;\n"
|
||||
"out vec2 texCoord_interp;\n"
|
||||
"\n"
|
||||
"vec2 normalize_coordinates()\n"
|
||||
"{\n"
|
||||
" return (vec2(2.0) * (pos / fullscreen)) - vec2(1.0);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_Position = vec4(normalize_coordinates(), 0.0, 1.0);\n"
|
||||
" texCoord_interp = texCoord;\n"
|
||||
"}\n\0";
|
||||
|
||||
static const char *FALLBACK_FRAGMENT_SHADER =
|
||||
"#version 330\n"
|
||||
"uniform sampler2D image_texture;\n"
|
||||
"in vec2 texCoord_interp;\n"
|
||||
"out vec4 fragColor;\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" fragColor = texture(image_texture, texCoord_interp);\n"
|
||||
"}\n\0";
|
||||
|
||||
static void shader_print_errors(const char *task, const char *log, const char *code)
|
||||
{
|
||||
LOG(ERROR) << "Shader: " << task << " error:";
|
||||
LOG(ERROR) << "===== shader string ====";
|
||||
|
||||
stringstream stream(code);
|
||||
string partial;
|
||||
|
||||
int line = 1;
|
||||
while (getline(stream, partial, '\n')) {
|
||||
if (line < 10) {
|
||||
LOG(ERROR) << " " << line << " " << partial;
|
||||
}
|
||||
else {
|
||||
LOG(ERROR) << line << " " << partial;
|
||||
}
|
||||
line++;
|
||||
}
|
||||
LOG(ERROR) << log;
|
||||
}
|
||||
|
||||
static int compile_fallback_shader(void)
|
||||
{
|
||||
const struct Shader {
|
||||
const char *source;
|
||||
const GLenum type;
|
||||
} shaders[2] = {{FALLBACK_VERTEX_SHADER, GL_VERTEX_SHADER},
|
||||
{FALLBACK_FRAGMENT_SHADER, GL_FRAGMENT_SHADER}};
|
||||
|
||||
const GLuint program = glCreateProgram();
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
const GLuint shader = glCreateShader(shaders[i].type);
|
||||
|
||||
string source_str = shaders[i].source;
|
||||
const char *c_str = source_str.c_str();
|
||||
|
||||
glShaderSource(shader, 1, &c_str, NULL);
|
||||
glCompileShader(shader);
|
||||
|
||||
GLint compile_status;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
|
||||
|
||||
if (!compile_status) {
|
||||
GLchar log[5000];
|
||||
GLsizei length = 0;
|
||||
glGetShaderInfoLog(shader, sizeof(log), &length, log);
|
||||
shader_print_errors("compile", log, c_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
glAttachShader(program, shader);
|
||||
}
|
||||
|
||||
/* Link output. */
|
||||
glBindFragDataLocation(program, 0, "fragColor");
|
||||
|
||||
/* Link and error check. */
|
||||
glLinkProgram(program);
|
||||
|
||||
/* TODO(sergey): Find a way to nicely de-duplicate the error checking. */
|
||||
GLint link_status;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &link_status);
|
||||
if (!link_status) {
|
||||
GLchar log[5000];
|
||||
GLsizei length = 0;
|
||||
/* TODO(sergey): Is it really program passed to glGetShaderInfoLog? */
|
||||
glGetShaderInfoLog(program, sizeof(log), &length, log);
|
||||
shader_print_errors("linking", log, FALLBACK_VERTEX_SHADER);
|
||||
shader_print_errors("linking", log, FALLBACK_FRAGMENT_SHADER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
void BlenderFallbackDisplayShader::bind(int width, int height)
|
||||
{
|
||||
create_shader_if_needed();
|
||||
|
||||
if (!shader_program_) {
|
||||
return;
|
||||
}
|
||||
|
||||
glUseProgram(shader_program_);
|
||||
glUniform1i(image_texture_location_, 0);
|
||||
glUniform2f(fullscreen_location_, width, height);
|
||||
}
|
||||
|
||||
void BlenderFallbackDisplayShader::unbind()
|
||||
{
|
||||
}
|
||||
|
||||
uint BlenderFallbackDisplayShader::get_shader_program()
|
||||
{
|
||||
return shader_program_;
|
||||
}
|
||||
|
||||
void BlenderFallbackDisplayShader::create_shader_if_needed()
|
||||
{
|
||||
if (shader_program_ || shader_compile_attempted_) {
|
||||
return;
|
||||
}
|
||||
|
||||
shader_compile_attempted_ = true;
|
||||
|
||||
shader_program_ = compile_fallback_shader();
|
||||
if (!shader_program_) {
|
||||
return;
|
||||
}
|
||||
|
||||
glUseProgram(shader_program_);
|
||||
|
||||
image_texture_location_ = glGetUniformLocation(shader_program_, "image_texture");
|
||||
if (image_texture_location_ < 0) {
|
||||
LOG(ERROR) << "Shader doesn't contain the 'image_texture' uniform.";
|
||||
destroy_shader();
|
||||
return;
|
||||
}
|
||||
|
||||
fullscreen_location_ = glGetUniformLocation(shader_program_, "fullscreen");
|
||||
if (fullscreen_location_ < 0) {
|
||||
LOG(ERROR) << "Shader doesn't contain the 'fullscreen' uniform.";
|
||||
destroy_shader();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void BlenderFallbackDisplayShader::destroy_shader()
|
||||
{
|
||||
glDeleteProgram(shader_program_);
|
||||
shader_program_ = 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* BlenderDisplaySpaceShader.
|
||||
*/
|
||||
|
||||
BlenderDisplaySpaceShader::BlenderDisplaySpaceShader(BL::RenderEngine &b_engine,
|
||||
BL::Scene &b_scene)
|
||||
: b_engine_(b_engine), b_scene_(b_scene)
|
||||
{
|
||||
DCHECK(b_engine_.support_display_space_shader(b_scene_));
|
||||
}
|
||||
|
||||
void BlenderDisplaySpaceShader::bind(int /*width*/, int /*height*/)
|
||||
{
|
||||
b_engine_.bind_display_space_shader(b_scene_);
|
||||
}
|
||||
|
||||
void BlenderDisplaySpaceShader::unbind()
|
||||
{
|
||||
b_engine_.unbind_display_space_shader();
|
||||
}
|
||||
|
||||
uint BlenderDisplaySpaceShader::get_shader_program()
|
||||
{
|
||||
if (!shader_program_) {
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, reinterpret_cast<int *>(&shader_program_));
|
||||
}
|
||||
|
||||
if (!shader_program_) {
|
||||
LOG(ERROR) << "Error retrieving shader program for display space shader.";
|
||||
}
|
||||
|
||||
return shader_program_;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* BlenderGPUDisplay.
|
||||
*/
|
||||
|
||||
BlenderGPUDisplay::BlenderGPUDisplay(BL::RenderEngine &b_engine, BL::Scene &b_scene)
|
||||
: b_engine_(b_engine), display_shader_(BlenderDisplayShader::create(b_engine, b_scene))
|
||||
{
|
||||
/* Create context while on the main thread. */
|
||||
gl_context_create();
|
||||
}
|
||||
|
||||
BlenderGPUDisplay::~BlenderGPUDisplay()
|
||||
{
|
||||
gl_resources_destroy();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Update procedure.
|
||||
*/
|
||||
|
||||
bool BlenderGPUDisplay::do_update_begin(const GPUDisplayParams ¶ms,
|
||||
int texture_width,
|
||||
int texture_height)
|
||||
{
|
||||
/* Note that it's the responsibility of BlenderGPUDisplay to ensure updating and drawing
|
||||
* the texture does not happen at the same time. This is achieved indirectly.
|
||||
*
|
||||
* When enabling the OpenGL context, it uses an internal mutex lock DST.gl_context_lock.
|
||||
* This same lock is also held when do_draw() is called, which together ensure mutual
|
||||
* exclusion.
|
||||
*
|
||||
* This locking is not performed at the GPU display level, because that would cause lock
|
||||
* inversion. */
|
||||
if (!gl_context_enable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gl_render_sync_) {
|
||||
glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
|
||||
}
|
||||
|
||||
if (!gl_texture_resources_ensure()) {
|
||||
gl_context_disable();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Update texture dimensions if needed. */
|
||||
if (texture_.width != texture_width || texture_.height != texture_height) {
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D, 0, GL_RGBA16F, texture_width, texture_height, 0, GL_RGBA, GL_HALF_FLOAT, 0);
|
||||
texture_.width = texture_width;
|
||||
texture_.height = texture_height;
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
/* Texture did change, and no pixel storage was provided. Tag for an explicit zeroing out to
|
||||
* avoid undefined content. */
|
||||
texture_.need_clear = true;
|
||||
}
|
||||
|
||||
/* Update PBO dimensions if needed.
|
||||
*
|
||||
* NOTE: Allocate the PBO for the the size which will fit the final render resolution (as in,
|
||||
* at a resolution divider 1. This was we don't need to recreate graphics interoperability
|
||||
* objects which are costly and which are tied to the specific underlying buffer size.
|
||||
* The downside of this approach is that when graphics interoperability is not used we are
|
||||
* sending too much data to GPU when resolution divider is not 1. */
|
||||
/* TODO(sergey): Investigate whether keeping the PBO exact size of the texture makes non-interop
|
||||
* mode faster. */
|
||||
const int buffer_width = params.full_size.x;
|
||||
const int buffer_height = params.full_size.y;
|
||||
if (texture_.buffer_width != buffer_width || texture_.buffer_height != buffer_height) {
|
||||
const size_t size_in_bytes = sizeof(half4) * buffer_width * buffer_height;
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, size_in_bytes, 0, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
|
||||
texture_.buffer_width = buffer_width;
|
||||
texture_.buffer_height = buffer_height;
|
||||
}
|
||||
|
||||
/* New content will be provided to the texture in one way or another, so mark this in a
|
||||
* centralized place. */
|
||||
texture_.need_update = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BlenderGPUDisplay::do_update_end()
|
||||
{
|
||||
gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
glFlush();
|
||||
|
||||
gl_context_disable();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Texture update from CPU buffer.
|
||||
*/
|
||||
|
||||
void BlenderGPUDisplay::do_copy_pixels_to_texture(
|
||||
const half4 *rgba_pixels, int texture_x, int texture_y, int pixels_width, int pixels_height)
|
||||
{
|
||||
/* This call copies pixels to a Pixel Buffer Object (PBO) which is much cheaper from CPU time
|
||||
* point of view than to copy data directly to the OpenGL texture.
|
||||
*
|
||||
* The possible downside of this approach is that it might require a higher peak memory when
|
||||
* doing partial updates of the texture (although, in practice even partial updates might peak
|
||||
* with a full-frame buffer stored on the CPU if the GPU is currently occupied). */
|
||||
|
||||
half4 *mapped_rgba_pixels = map_texture_buffer();
|
||||
if (!mapped_rgba_pixels) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (texture_x == 0 && texture_y == 0 && pixels_width == texture_.width &&
|
||||
pixels_height == texture_.height) {
|
||||
const size_t size_in_bytes = sizeof(half4) * texture_.width * texture_.height;
|
||||
memcpy(mapped_rgba_pixels, rgba_pixels, size_in_bytes);
|
||||
}
|
||||
else {
|
||||
const half4 *rgba_row = rgba_pixels;
|
||||
half4 *mapped_rgba_row = mapped_rgba_pixels + texture_y * texture_.width + texture_x;
|
||||
for (int y = 0; y < pixels_height;
|
||||
++y, rgba_row += pixels_width, mapped_rgba_row += texture_.width) {
|
||||
memcpy(mapped_rgba_row, rgba_row, sizeof(half4) * pixels_width);
|
||||
}
|
||||
}
|
||||
|
||||
unmap_texture_buffer();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Texture buffer mapping.
|
||||
*/
|
||||
|
||||
half4 *BlenderGPUDisplay::do_map_texture_buffer()
|
||||
{
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
|
||||
|
||||
half4 *mapped_rgba_pixels = reinterpret_cast<half4 *>(
|
||||
glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));
|
||||
if (!mapped_rgba_pixels) {
|
||||
LOG(ERROR) << "Error mapping BlenderGPUDisplay pixel buffer object.";
|
||||
}
|
||||
|
||||
if (texture_.need_clear) {
|
||||
const int64_t texture_width = texture_.width;
|
||||
const int64_t texture_height = texture_.height;
|
||||
memset(reinterpret_cast<void *>(mapped_rgba_pixels),
|
||||
0,
|
||||
texture_width * texture_height * sizeof(half4));
|
||||
texture_.need_clear = false;
|
||||
}
|
||||
|
||||
return mapped_rgba_pixels;
|
||||
}
|
||||
|
||||
void BlenderGPUDisplay::do_unmap_texture_buffer()
|
||||
{
|
||||
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Graphics interoperability.
|
||||
*/
|
||||
|
||||
DeviceGraphicsInteropDestination BlenderGPUDisplay::do_graphics_interop_get()
|
||||
{
|
||||
DeviceGraphicsInteropDestination interop_dst;
|
||||
|
||||
interop_dst.buffer_width = texture_.buffer_width;
|
||||
interop_dst.buffer_height = texture_.buffer_height;
|
||||
interop_dst.opengl_pbo_id = texture_.gl_pbo_id;
|
||||
|
||||
interop_dst.need_clear = texture_.need_clear;
|
||||
texture_.need_clear = false;
|
||||
|
||||
return interop_dst;
|
||||
}
|
||||
|
||||
void BlenderGPUDisplay::graphics_interop_activate()
|
||||
{
|
||||
gl_context_enable();
|
||||
}
|
||||
|
||||
void BlenderGPUDisplay::graphics_interop_deactivate()
|
||||
{
|
||||
gl_context_disable();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Drawing.
|
||||
*/
|
||||
|
||||
void BlenderGPUDisplay::clear()
|
||||
{
|
||||
texture_.need_clear = true;
|
||||
}
|
||||
|
||||
void BlenderGPUDisplay::set_zoom(float zoom_x, float zoom_y)
|
||||
{
|
||||
zoom_ = make_float2(zoom_x, zoom_y);
|
||||
}
|
||||
|
||||
void BlenderGPUDisplay::do_draw(const GPUDisplayParams ¶ms)
|
||||
{
|
||||
/* See do_update_begin() for why no locking is required here. */
|
||||
const bool transparent = true; // TODO(sergey): Derive this from Film.
|
||||
|
||||
if (texture_.need_clear) {
|
||||
/* Texture is requested to be cleared and was not yet cleared.
|
||||
* Do early return which should be equivalent of drawing all-zero texture. */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gl_draw_resources_ensure()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (use_gl_context_) {
|
||||
gl_context_mutex_.lock();
|
||||
}
|
||||
|
||||
if (gl_upload_sync_) {
|
||||
glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
|
||||
}
|
||||
|
||||
if (transparent) {
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
display_shader_->bind(params.full_size.x, params.full_size.y);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
|
||||
|
||||
/* Trick to keep sharp rendering without jagged edges on all GPUs.
|
||||
*
|
||||
* The idea here is to enforce driver to use linear interpolation when the image is not zoomed
|
||||
* in.
|
||||
* For the render result with a resolution divider in effect we always use nearest interpolation.
|
||||
*
|
||||
* Use explicit MIN assignment to make sure the driver does not have an undefined behavior at
|
||||
* the zoom level 1. The MAG filter is always NEAREST. */
|
||||
const float zoomed_width = params.size.x * zoom_.x;
|
||||
const float zoomed_height = params.size.y * zoom_.y;
|
||||
if (texture_.width != params.size.x || texture_.height != params.size.y) {
|
||||
/* Resolution divider is different from 1, force enarest interpolation. */
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}
|
||||
else if (zoomed_width - params.size.x > 0.5f || zoomed_height - params.size.y > 0.5f) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}
|
||||
else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
|
||||
|
||||
texture_update_if_needed();
|
||||
vertex_buffer_update(params);
|
||||
|
||||
/* TODO(sergey): Does it make sense/possible to cache/reuse the VAO? */
|
||||
GLuint vertex_array_object;
|
||||
glGenVertexArrays(1, &vertex_array_object);
|
||||
glBindVertexArray(vertex_array_object);
|
||||
|
||||
const int texcoord_attribute = display_shader_->get_tex_coord_attrib_location();
|
||||
const int position_attribute = display_shader_->get_position_attrib_location();
|
||||
|
||||
glEnableVertexAttribArray(texcoord_attribute);
|
||||
glEnableVertexAttribArray(position_attribute);
|
||||
|
||||
glVertexAttribPointer(
|
||||
texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0);
|
||||
glVertexAttribPointer(position_attribute,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
4 * sizeof(float),
|
||||
(const GLvoid *)(sizeof(float) * 2));
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glDeleteVertexArrays(1, &vertex_array_object);
|
||||
|
||||
display_shader_->unbind();
|
||||
|
||||
if (transparent) {
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
glFlush();
|
||||
|
||||
if (use_gl_context_) {
|
||||
gl_context_mutex_.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void BlenderGPUDisplay::gl_context_create()
|
||||
{
|
||||
/* When rendering in viewport there is no render context available via engine.
|
||||
* Check whether own context is to be created here.
|
||||
*
|
||||
* NOTE: If the `b_engine_`'s context is not available, we are expected to be on a main thread
|
||||
* here. */
|
||||
use_gl_context_ = !RE_engine_has_render_context(
|
||||
reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
|
||||
|
||||
if (use_gl_context_) {
|
||||
const bool drw_state = DRW_opengl_context_release();
|
||||
gl_context_ = WM_opengl_context_create();
|
||||
if (gl_context_) {
|
||||
/* On Windows an old context is restored after creation, and subsequent release of context
|
||||
* generates a Win32 error. Harmless for users, but annoying to have possible misleading
|
||||
* error prints in the console. */
|
||||
#ifndef _WIN32
|
||||
WM_opengl_context_release(gl_context_);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
LOG(ERROR) << "Error creating OpenGL context.";
|
||||
}
|
||||
|
||||
DRW_opengl_context_activate(drw_state);
|
||||
}
|
||||
}
|
||||
|
||||
bool BlenderGPUDisplay::gl_context_enable()
|
||||
{
|
||||
if (use_gl_context_) {
|
||||
if (!gl_context_) {
|
||||
return false;
|
||||
}
|
||||
gl_context_mutex_.lock();
|
||||
WM_opengl_context_activate(gl_context_);
|
||||
return true;
|
||||
}
|
||||
|
||||
RE_engine_render_context_enable(reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
|
||||
return true;
|
||||
}
|
||||
|
||||
void BlenderGPUDisplay::gl_context_disable()
|
||||
{
|
||||
if (use_gl_context_) {
|
||||
if (gl_context_) {
|
||||
WM_opengl_context_release(gl_context_);
|
||||
gl_context_mutex_.unlock();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
RE_engine_render_context_disable(reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
|
||||
}
|
||||
|
||||
void BlenderGPUDisplay::gl_context_dispose()
|
||||
{
|
||||
if (gl_context_) {
|
||||
const bool drw_state = DRW_opengl_context_release();
|
||||
|
||||
WM_opengl_context_activate(gl_context_);
|
||||
WM_opengl_context_dispose(gl_context_);
|
||||
|
||||
DRW_opengl_context_activate(drw_state);
|
||||
}
|
||||
}
|
||||
|
||||
bool BlenderGPUDisplay::gl_draw_resources_ensure()
|
||||
{
|
||||
if (!texture_.gl_id) {
|
||||
/* If there is no texture allocated, there is nothing to draw. Inform the draw call that it can
|
||||
* can not continue. Note that this is not an unrecoverable error, so once the texture is known
|
||||
* we will come back here and create all the GPU resources needed for draw. */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gl_draw_resource_creation_attempted_) {
|
||||
return gl_draw_resources_created_;
|
||||
}
|
||||
gl_draw_resource_creation_attempted_ = true;
|
||||
|
||||
if (!vertex_buffer_) {
|
||||
glGenBuffers(1, &vertex_buffer_);
|
||||
if (!vertex_buffer_) {
|
||||
LOG(ERROR) << "Error creating vertex buffer.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
gl_draw_resources_created_ = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BlenderGPUDisplay::gl_resources_destroy()
|
||||
{
|
||||
gl_context_enable();
|
||||
|
||||
if (vertex_buffer_ != 0) {
|
||||
glDeleteBuffers(1, &vertex_buffer_);
|
||||
}
|
||||
|
||||
if (texture_.gl_pbo_id) {
|
||||
glDeleteBuffers(1, &texture_.gl_pbo_id);
|
||||
texture_.gl_pbo_id = 0;
|
||||
}
|
||||
|
||||
if (texture_.gl_id) {
|
||||
glDeleteTextures(1, &texture_.gl_id);
|
||||
texture_.gl_id = 0;
|
||||
}
|
||||
|
||||
gl_context_disable();
|
||||
|
||||
gl_context_dispose();
|
||||
}
|
||||
|
||||
bool BlenderGPUDisplay::gl_texture_resources_ensure()
|
||||
{
|
||||
if (texture_.creation_attempted) {
|
||||
return texture_.is_created;
|
||||
}
|
||||
texture_.creation_attempted = true;
|
||||
|
||||
DCHECK(!texture_.gl_id);
|
||||
DCHECK(!texture_.gl_pbo_id);
|
||||
|
||||
/* Create texture. */
|
||||
glGenTextures(1, &texture_.gl_id);
|
||||
if (!texture_.gl_id) {
|
||||
LOG(ERROR) << "Error creating texture.";
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Configure the texture. */
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
/* Create PBO for the texture. */
|
||||
glGenBuffers(1, &texture_.gl_pbo_id);
|
||||
if (!texture_.gl_pbo_id) {
|
||||
LOG(ERROR) << "Error creating texture pixel buffer object.";
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Creation finished with a success. */
|
||||
texture_.is_created = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BlenderGPUDisplay::texture_update_if_needed()
|
||||
{
|
||||
if (!texture_.need_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
|
||||
glTexSubImage2D(
|
||||
GL_TEXTURE_2D, 0, 0, 0, texture_.width, texture_.height, GL_RGBA, GL_HALF_FLOAT, 0);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
|
||||
texture_.need_update = false;
|
||||
}
|
||||
|
||||
void BlenderGPUDisplay::vertex_buffer_update(const GPUDisplayParams ¶ms)
|
||||
{
|
||||
/* Invalidate old contents - avoids stalling if the buffer is still waiting in queue to be
|
||||
* rendered. */
|
||||
glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW);
|
||||
|
||||
float *vpointer = reinterpret_cast<float *>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
|
||||
if (!vpointer) {
|
||||
return;
|
||||
}
|
||||
|
||||
vpointer[0] = 0.0f;
|
||||
vpointer[1] = 0.0f;
|
||||
vpointer[2] = params.offset.x;
|
||||
vpointer[3] = params.offset.y;
|
||||
|
||||
vpointer[4] = 1.0f;
|
||||
vpointer[5] = 0.0f;
|
||||
vpointer[6] = (float)params.size.x + params.offset.x;
|
||||
vpointer[7] = params.offset.y;
|
||||
|
||||
vpointer[8] = 1.0f;
|
||||
vpointer[9] = 1.0f;
|
||||
vpointer[10] = (float)params.size.x + params.offset.x;
|
||||
vpointer[11] = (float)params.size.y + params.offset.y;
|
||||
|
||||
vpointer[12] = 0.0f;
|
||||
vpointer[13] = 1.0f;
|
||||
vpointer[14] = params.offset.x;
|
||||
vpointer[15] = (float)params.size.y + params.offset.y;
|
||||
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
215
intern/cycles/blender/blender_gpu_display.h
Normal file
215
intern/cycles/blender/blender_gpu_display.h
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright 2021 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "RNA_blender_cpp.h"
|
||||
|
||||
#include "render/gpu_display.h"
|
||||
#include "util/util_unique_ptr.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Base class of shader used for GPU display rendering. */
|
||||
class BlenderDisplayShader {
|
||||
public:
|
||||
static constexpr const char *position_attribute_name = "pos";
|
||||
static constexpr const char *tex_coord_attribute_name = "texCoord";
|
||||
|
||||
/* Create shader implementation suitable for the given render engine and scene configuration. */
|
||||
static unique_ptr<BlenderDisplayShader> create(BL::RenderEngine &b_engine, BL::Scene &b_scene);
|
||||
|
||||
BlenderDisplayShader() = default;
|
||||
virtual ~BlenderDisplayShader() = default;
|
||||
|
||||
virtual void bind(int width, int height) = 0;
|
||||
virtual void unbind() = 0;
|
||||
|
||||
/* Get attribute location for position and texture coordinate respectively.
|
||||
* NOTE: The shader needs to be bound to have access to those. */
|
||||
virtual int get_position_attrib_location();
|
||||
virtual int get_tex_coord_attrib_location();
|
||||
|
||||
protected:
|
||||
/* Get program of this display shader.
|
||||
* NOTE: The shader needs to be bound to have access to this. */
|
||||
virtual uint get_shader_program() = 0;
|
||||
|
||||
/* Cached values of various OpenGL resources. */
|
||||
int position_attribute_location_ = -1;
|
||||
int tex_coord_attribute_location_ = -1;
|
||||
};
|
||||
|
||||
/* Implementation of display rendering shader used in the case when render engine does not support
|
||||
* display space shader. */
|
||||
class BlenderFallbackDisplayShader : public BlenderDisplayShader {
|
||||
public:
|
||||
virtual void bind(int width, int height) override;
|
||||
virtual void unbind() override;
|
||||
|
||||
protected:
|
||||
virtual uint get_shader_program() override;
|
||||
|
||||
void create_shader_if_needed();
|
||||
void destroy_shader();
|
||||
|
||||
uint shader_program_ = 0;
|
||||
int image_texture_location_ = -1;
|
||||
int fullscreen_location_ = -1;
|
||||
|
||||
/* Shader compilation attempted. Which means, that if the shader program is 0 then compilation or
|
||||
* linking has failed. Do not attempt to re-compile the shader. */
|
||||
bool shader_compile_attempted_ = false;
|
||||
};
|
||||
|
||||
class BlenderDisplaySpaceShader : public BlenderDisplayShader {
|
||||
public:
|
||||
BlenderDisplaySpaceShader(BL::RenderEngine &b_engine, BL::Scene &b_scene);
|
||||
|
||||
virtual void bind(int width, int height) override;
|
||||
virtual void unbind() override;
|
||||
|
||||
protected:
|
||||
virtual uint get_shader_program() override;
|
||||
|
||||
BL::RenderEngine b_engine_;
|
||||
BL::Scene &b_scene_;
|
||||
|
||||
/* Cached values of various OpenGL resources. */
|
||||
uint shader_program_ = 0;
|
||||
};
|
||||
|
||||
/* GPU display implementation which is specific for Blender viewport integration. */
|
||||
class BlenderGPUDisplay : public GPUDisplay {
|
||||
public:
|
||||
BlenderGPUDisplay(BL::RenderEngine &b_engine, BL::Scene &b_scene);
|
||||
~BlenderGPUDisplay();
|
||||
|
||||
virtual void graphics_interop_activate() override;
|
||||
virtual void graphics_interop_deactivate() override;
|
||||
|
||||
virtual void clear() override;
|
||||
|
||||
void set_zoom(float zoom_x, float zoom_y);
|
||||
|
||||
protected:
|
||||
virtual bool do_update_begin(const GPUDisplayParams ¶ms,
|
||||
int texture_width,
|
||||
int texture_height) override;
|
||||
virtual void do_update_end() override;
|
||||
|
||||
virtual void do_copy_pixels_to_texture(const half4 *rgba_pixels,
|
||||
int texture_x,
|
||||
int texture_y,
|
||||
int pixels_width,
|
||||
int pixels_height) override;
|
||||
virtual void do_draw(const GPUDisplayParams ¶ms) override;
|
||||
|
||||
virtual half4 *do_map_texture_buffer() override;
|
||||
virtual void do_unmap_texture_buffer() override;
|
||||
|
||||
virtual DeviceGraphicsInteropDestination do_graphics_interop_get() override;
|
||||
|
||||
/* Helper function which allocates new GPU context. */
|
||||
void gl_context_create();
|
||||
bool gl_context_enable();
|
||||
void gl_context_disable();
|
||||
void gl_context_dispose();
|
||||
|
||||
/* Make sure texture is allocated and its initial configuration is performed. */
|
||||
bool gl_texture_resources_ensure();
|
||||
|
||||
/* Ensure all runtime GPU resources needed for drawing are allocated.
|
||||
* Returns true if all resources needed for drawing are available. */
|
||||
bool gl_draw_resources_ensure();
|
||||
|
||||
/* Destroy all GPU resources which are being used by this object. */
|
||||
void gl_resources_destroy();
|
||||
|
||||
/* Update GPU texture dimensions and content if needed (new pixel data was provided).
|
||||
*
|
||||
* NOTE: The texture needs to be bound. */
|
||||
void texture_update_if_needed();
|
||||
|
||||
/* Update vertex buffer with new coordinates of vertex positions and texture coordinates.
|
||||
* This buffer is used to render texture in the viewport.
|
||||
*
|
||||
* NOTE: The buffer needs to be bound. */
|
||||
void vertex_buffer_update(const GPUDisplayParams ¶ms);
|
||||
|
||||
BL::RenderEngine b_engine_;
|
||||
|
||||
/* OpenGL context which is used the render engine doesn't have its own. */
|
||||
void *gl_context_ = nullptr;
|
||||
/* The when Blender RenderEngine side context is not available and the GPUDisplay is to create
|
||||
* its own context. */
|
||||
bool use_gl_context_ = false;
|
||||
/* Mutex used to guard the `gl_context_`. */
|
||||
thread_mutex gl_context_mutex_;
|
||||
|
||||
/* Texture which contains pixels of the render result. */
|
||||
struct {
|
||||
/* Indicates whether texture creation was attempted and succeeded.
|
||||
* Used to avoid multiple attempts of texture creation on GPU issues or GPU context
|
||||
* misconfiguration. */
|
||||
bool creation_attempted = false;
|
||||
bool is_created = false;
|
||||
|
||||
/* OpenGL resource IDs of the texture itself and Pixel Buffer Object (PBO) used to write
|
||||
* pixels to it.
|
||||
*
|
||||
* NOTE: Allocated on the engine's context. */
|
||||
uint gl_id = 0;
|
||||
uint gl_pbo_id = 0;
|
||||
|
||||
/* Is true when new data was written to the PBO, meaning, the texture might need to be resized
|
||||
* and new data is to be uploaded to the GPU. */
|
||||
bool need_update = false;
|
||||
|
||||
/* Content of the texture is to be filled with zeroes. */
|
||||
std::atomic<bool> need_clear = true;
|
||||
|
||||
/* Dimensions of the texture in pixels. */
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
/* Dimensions of the underlying PBO. */
|
||||
int buffer_width = 0;
|
||||
int buffer_height = 0;
|
||||
} texture_;
|
||||
|
||||
unique_ptr<BlenderDisplayShader> display_shader_;
|
||||
|
||||
/* Special track of whether GPU resources were attempted to be created, to avoid attempts of
|
||||
* their re-creation on failure on every redraw. */
|
||||
bool gl_draw_resource_creation_attempted_ = false;
|
||||
bool gl_draw_resources_created_ = false;
|
||||
|
||||
/* Vertex buffer which hold vertices of a triangle fan which is textures with the texture
|
||||
* holding the render result. */
|
||||
uint vertex_buffer_ = 0;
|
||||
|
||||
void *gl_render_sync_ = nullptr;
|
||||
void *gl_upload_sync_ = nullptr;
|
||||
|
||||
float2 zoom_ = make_float2(1.0f, 1.0f);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
@@ -27,15 +27,14 @@ CCL_NAMESPACE_BEGIN
|
||||
|
||||
void BlenderSync::sync_light(BL::Object &b_parent,
|
||||
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
|
||||
BL::Object &b_ob,
|
||||
BL::Object &b_ob_instance,
|
||||
BObjectInfo &b_ob_info,
|
||||
int random_id,
|
||||
Transform &tfm,
|
||||
bool *use_portal)
|
||||
{
|
||||
/* test if we need to sync */
|
||||
ObjectKey key(b_parent, persistent_id, b_ob_instance, false);
|
||||
BL::Light b_light(b_ob.data());
|
||||
ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, false);
|
||||
BL::Light b_light(b_ob_info.object_data);
|
||||
|
||||
Light *light = light_map.find(key);
|
||||
|
||||
@@ -44,7 +43,7 @@ void BlenderSync::sync_light(BL::Object &b_parent,
|
||||
const bool tfm_updated = (light && light->get_tfm() != tfm);
|
||||
|
||||
/* Update if either object or light data changed. */
|
||||
if (!light_map.add_or_update(&light, b_ob, b_parent, key) && !tfm_updated) {
|
||||
if (!light_map.add_or_update(&light, b_ob_info.real_object, b_parent, key) && !tfm_updated) {
|
||||
Shader *shader;
|
||||
if (!shader_map.add_or_update(&shader, b_light)) {
|
||||
if (light->get_is_portal())
|
||||
@@ -126,24 +125,17 @@ void BlenderSync::sync_light(BL::Object &b_parent,
|
||||
light->set_shader(static_cast<Shader *>(used_shaders[0]));
|
||||
|
||||
/* shadow */
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles");
|
||||
light->set_cast_shadow(get_boolean(clight, "cast_shadow"));
|
||||
light->set_use_mis(get_boolean(clight, "use_multiple_importance_sampling"));
|
||||
|
||||
int samples = get_int(clight, "samples");
|
||||
if (get_boolean(cscene, "use_square_samples"))
|
||||
light->set_samples(samples * samples);
|
||||
else
|
||||
light->set_samples(samples);
|
||||
|
||||
light->set_max_bounces(get_int(clight, "max_bounces"));
|
||||
|
||||
if (b_ob != b_ob_instance) {
|
||||
if (b_ob_info.real_object != b_ob_info.iter_object) {
|
||||
light->set_random_id(random_id);
|
||||
}
|
||||
else {
|
||||
light->set_random_id(hash_uint2(hash_string(b_ob.name().c_str()), 0));
|
||||
light->set_random_id(hash_uint2(hash_string(b_ob_info.real_object.name().c_str()), 0));
|
||||
}
|
||||
|
||||
if (light->get_light_type() == LIGHT_AREA)
|
||||
@@ -155,11 +147,13 @@ void BlenderSync::sync_light(BL::Object &b_parent,
|
||||
*use_portal = true;
|
||||
|
||||
/* visibility */
|
||||
uint visibility = object_ray_visibility(b_ob);
|
||||
uint visibility = object_ray_visibility(b_ob_info.real_object);
|
||||
light->set_use_camera((visibility & PATH_RAY_CAMERA) != 0);
|
||||
light->set_use_diffuse((visibility & PATH_RAY_DIFFUSE) != 0);
|
||||
light->set_use_glossy((visibility & PATH_RAY_GLOSSY) != 0);
|
||||
light->set_use_transmission((visibility & PATH_RAY_TRANSMIT) != 0);
|
||||
light->set_use_scatter((visibility & PATH_RAY_VOLUME_SCATTER) != 0);
|
||||
light->set_is_shadow_catcher(b_ob_info.real_object.is_shadow_catcher());
|
||||
|
||||
/* tag */
|
||||
light->tag_update(scene);
|
||||
@@ -170,7 +164,6 @@ void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal)
|
||||
BL::World b_world = b_scene.world();
|
||||
|
||||
if (b_world) {
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
|
||||
|
||||
enum SamplingMethod { SAMPLING_NONE = 0, SAMPLING_AUTOMATIC, SAMPLING_MANUAL, SAMPLING_NUM };
|
||||
@@ -198,12 +191,6 @@ void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal)
|
||||
/* force enable light again when world is resynced */
|
||||
light->set_is_enabled(true);
|
||||
|
||||
int samples = get_int(cworld, "samples");
|
||||
if (get_boolean(cscene, "use_square_samples"))
|
||||
light->set_samples(samples * samples);
|
||||
else
|
||||
light->set_samples(samples);
|
||||
|
||||
light->tag_update(scene);
|
||||
light_map.set_recalc(b_world);
|
||||
}
|
||||
@@ -212,7 +199,7 @@ void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal)
|
||||
|
||||
world_map = b_world.ptr.data;
|
||||
world_recalc = false;
|
||||
viewport_parameters = BlenderViewportParameters(b_v3d);
|
||||
viewport_parameters = BlenderViewportParameters(b_v3d, use_developer_ui);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -347,16 +347,57 @@ static void fill_generic_attribute(BL::Mesh &b_mesh,
|
||||
}
|
||||
}
|
||||
|
||||
static void attr_create_generic(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision)
|
||||
static void attr_create_motion(Mesh *mesh, BL::Attribute &b_attribute, const float motion_scale)
|
||||
{
|
||||
if (!(b_attribute.domain() == BL::Attribute::domain_POINT) &&
|
||||
(b_attribute.data_type() == BL::Attribute::data_type_FLOAT_VECTOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BL::FloatVectorAttribute b_vector_attribute(b_attribute);
|
||||
const int numverts = mesh->get_verts().size();
|
||||
|
||||
/* Find or add attribute */
|
||||
float3 *P = &mesh->get_verts()[0];
|
||||
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
|
||||
if (!attr_mP) {
|
||||
attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
}
|
||||
|
||||
/* Only export previous and next frame, we don't have any in between data. */
|
||||
float motion_times[2] = {-1.0f, 1.0f};
|
||||
for (int step = 0; step < 2; step++) {
|
||||
const float relative_time = motion_times[step] * 0.5f * motion_scale;
|
||||
float3 *mP = attr_mP->data_float3() + step * numverts;
|
||||
|
||||
for (int i = 0; i < numverts; i++) {
|
||||
mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void attr_create_generic(Scene *scene,
|
||||
Mesh *mesh,
|
||||
BL::Mesh &b_mesh,
|
||||
const bool subdivision,
|
||||
const bool need_motion,
|
||||
const float motion_scale)
|
||||
{
|
||||
if (subdivision) {
|
||||
/* TODO: Handle subdivision correctly. */
|
||||
return;
|
||||
}
|
||||
AttributeSet &attributes = mesh->attributes;
|
||||
static const ustring u_velocity("velocity");
|
||||
|
||||
for (BL::Attribute &b_attribute : b_mesh.attributes) {
|
||||
const ustring name{b_attribute.name().c_str()};
|
||||
|
||||
if (need_motion && name == u_velocity) {
|
||||
attr_create_motion(mesh, b_attribute, motion_scale);
|
||||
}
|
||||
|
||||
if (!mesh->need_attribute(scene, name)) {
|
||||
continue;
|
||||
}
|
||||
@@ -859,8 +900,10 @@ static void create_mesh(Scene *scene,
|
||||
Mesh *mesh,
|
||||
BL::Mesh &b_mesh,
|
||||
const array<Node *> &used_shaders,
|
||||
bool subdivision = false,
|
||||
bool subdivide_uvs = true)
|
||||
const bool need_motion,
|
||||
const float motion_scale,
|
||||
const bool subdivision = false,
|
||||
const bool subdivide_uvs = true)
|
||||
{
|
||||
/* count vertices and faces */
|
||||
int numverts = b_mesh.vertices.length();
|
||||
@@ -974,7 +1017,7 @@ static void create_mesh(Scene *scene,
|
||||
attr_create_vertex_color(scene, mesh, b_mesh, subdivision);
|
||||
attr_create_sculpt_vertex_color(scene, mesh, b_mesh, subdivision);
|
||||
attr_create_random_per_island(scene, mesh, b_mesh, subdivision);
|
||||
attr_create_generic(scene, mesh, b_mesh, subdivision);
|
||||
attr_create_generic(scene, mesh, b_mesh, subdivision, need_motion, motion_scale);
|
||||
|
||||
if (subdivision) {
|
||||
attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs);
|
||||
@@ -999,16 +1042,20 @@ static void create_mesh(Scene *scene,
|
||||
|
||||
static void create_subd_mesh(Scene *scene,
|
||||
Mesh *mesh,
|
||||
BL::Object &b_ob,
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Mesh &b_mesh,
|
||||
const array<Node *> &used_shaders,
|
||||
const bool need_motion,
|
||||
const float motion_scale,
|
||||
float dicing_rate,
|
||||
int max_subdivisions)
|
||||
{
|
||||
BL::Object b_ob = b_ob_info.real_object;
|
||||
|
||||
BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length() - 1]);
|
||||
bool subdivide_uvs = subsurf_mod.uv_smooth() != BL::SubsurfModifier::uv_smooth_NONE;
|
||||
|
||||
create_mesh(scene, mesh, b_mesh, used_shaders, true, subdivide_uvs);
|
||||
create_mesh(scene, mesh, b_mesh, used_shaders, need_motion, motion_scale, true, subdivide_uvs);
|
||||
|
||||
/* export creases */
|
||||
size_t num_creases = 0;
|
||||
@@ -1043,7 +1090,7 @@ static void create_subd_mesh(Scene *scene,
|
||||
*
|
||||
* NOTE: This code is run prior to object motion blur initialization. so can not access properties
|
||||
* set by `sync_object_motion_init()`. */
|
||||
static bool mesh_need_motion_attribute(BL::Object &b_ob, Scene *scene)
|
||||
static bool mesh_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
|
||||
{
|
||||
const Scene::MotionType need_motion = scene->need_motion();
|
||||
if (need_motion == Scene::MOTION_NONE) {
|
||||
@@ -1060,7 +1107,7 @@ static bool mesh_need_motion_attribute(BL::Object &b_ob, Scene *scene)
|
||||
* - Motion attribute expects non-zero time steps.
|
||||
*
|
||||
* Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */
|
||||
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
|
||||
PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles");
|
||||
const bool use_motion = get_boolean(cobject, "use_motion_blur");
|
||||
if (!use_motion) {
|
||||
return false;
|
||||
@@ -1072,92 +1119,7 @@ static bool mesh_need_motion_attribute(BL::Object &b_ob, Scene *scene)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sync_mesh_cached_velocities(BL::Object &b_ob, Scene *scene, Mesh *mesh)
|
||||
{
|
||||
if (!mesh_need_motion_attribute(b_ob, scene)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BL::MeshSequenceCacheModifier b_mesh_cache = object_mesh_cache_find(b_ob, true, nullptr);
|
||||
|
||||
if (!b_mesh_cache) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MeshSequenceCacheModifier_read_velocity_get(&b_mesh_cache.ptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t numverts = mesh->get_verts().size();
|
||||
|
||||
if (b_mesh_cache.vertex_velocities.length() != numverts) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find or add attribute */
|
||||
float3 *P = &mesh->get_verts()[0];
|
||||
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
|
||||
if (!attr_mP) {
|
||||
attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
}
|
||||
|
||||
/* Only export previous and next frame, we don't have any in between data. */
|
||||
float motion_times[2] = {-1.0f, 1.0f};
|
||||
for (int step = 0; step < 2; step++) {
|
||||
const float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f;
|
||||
float3 *mP = attr_mP->data_float3() + step * numverts;
|
||||
|
||||
BL::MeshSequenceCacheModifier::vertex_velocities_iterator vvi;
|
||||
int i = 0;
|
||||
|
||||
for (b_mesh_cache.vertex_velocities.begin(vvi); vvi != b_mesh_cache.vertex_velocities.end();
|
||||
++vvi, ++i) {
|
||||
mP[i] = P[i] + get_float3(vvi->velocity()) * relative_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh)
|
||||
{
|
||||
if (!mesh_need_motion_attribute(b_ob, scene)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob);
|
||||
|
||||
if (!b_fluid_domain)
|
||||
return;
|
||||
|
||||
/* If the mesh has modifiers following the fluid domain we can't export motion. */
|
||||
if (b_fluid_domain.mesh_vertices.length() != mesh->get_verts().size())
|
||||
return;
|
||||
|
||||
/* Find or add attribute */
|
||||
float3 *P = &mesh->get_verts()[0];
|
||||
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
|
||||
if (!attr_mP) {
|
||||
attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
}
|
||||
|
||||
/* Only export previous and next frame, we don't have any in between data. */
|
||||
float motion_times[2] = {-1.0f, 1.0f};
|
||||
for (int step = 0; step < 2; step++) {
|
||||
float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f;
|
||||
float3 *mP = attr_mP->data_float3() + step * mesh->get_verts().size();
|
||||
|
||||
BL::FluidDomainSettings::mesh_vertices_iterator svi;
|
||||
int i = 0;
|
||||
|
||||
for (b_fluid_domain.mesh_vertices.begin(svi); svi != b_fluid_domain.mesh_vertices.end();
|
||||
++svi, ++i) {
|
||||
mP[i] = P[i] + get_float3(svi->velocity()) * relative_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh)
|
||||
void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh)
|
||||
{
|
||||
/* make a copy of the shaders as the caller in the main thread still need them for syncing the
|
||||
* attributes */
|
||||
@@ -1170,37 +1132,47 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *me
|
||||
/* Adaptive subdivision setup. Not for baking since that requires
|
||||
* exact mapping to the Blender mesh. */
|
||||
if (!scene->bake_manager->get_baking()) {
|
||||
new_mesh.set_subdivision_type(object_subdivision_type(b_ob, preview, experimental));
|
||||
new_mesh.set_subdivision_type(
|
||||
object_subdivision_type(b_ob_info.real_object, preview, experimental));
|
||||
}
|
||||
|
||||
/* For some reason, meshes do not need this... */
|
||||
bool need_undeformed = new_mesh.need_attribute(scene, ATTR_STD_GENERATED);
|
||||
BL::Mesh b_mesh = object_to_mesh(
|
||||
b_data, b_ob, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type());
|
||||
b_data, b_ob_info, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type());
|
||||
|
||||
if (b_mesh) {
|
||||
/* Motion blur attribute is relative to seconds, we need it relative to frames. */
|
||||
const bool need_motion = mesh_need_motion_attribute(b_ob_info, scene);
|
||||
const float motion_scale = (need_motion) ?
|
||||
scene->motion_shutter_time() /
|
||||
(b_scene.render().fps() / b_scene.render().fps_base()) :
|
||||
0.0f;
|
||||
|
||||
/* Sync mesh itself. */
|
||||
if (new_mesh.get_subdivision_type() != Mesh::SUBDIVISION_NONE)
|
||||
create_subd_mesh(scene,
|
||||
&new_mesh,
|
||||
b_ob,
|
||||
b_ob_info,
|
||||
b_mesh,
|
||||
new_mesh.get_used_shaders(),
|
||||
need_motion,
|
||||
motion_scale,
|
||||
dicing_rate,
|
||||
max_subdivisions);
|
||||
else
|
||||
create_mesh(scene, &new_mesh, b_mesh, new_mesh.get_used_shaders(), false);
|
||||
create_mesh(scene,
|
||||
&new_mesh,
|
||||
b_mesh,
|
||||
new_mesh.get_used_shaders(),
|
||||
need_motion,
|
||||
motion_scale,
|
||||
false);
|
||||
|
||||
free_object_to_mesh(b_data, b_ob, b_mesh);
|
||||
free_object_to_mesh(b_data, b_ob_info, b_mesh);
|
||||
}
|
||||
}
|
||||
|
||||
/* cached velocities (e.g. from alembic archive) */
|
||||
sync_mesh_cached_velocities(b_ob, scene, &new_mesh);
|
||||
|
||||
/* mesh fluid motion mantaflow */
|
||||
sync_mesh_fluid_motion(b_ob, scene, &new_mesh);
|
||||
|
||||
/* update original sockets */
|
||||
|
||||
mesh->clear_non_sockets();
|
||||
@@ -1230,22 +1202,10 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *me
|
||||
}
|
||||
|
||||
void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
||||
BL::Object b_ob,
|
||||
BObjectInfo &b_ob_info,
|
||||
Mesh *mesh,
|
||||
int motion_step)
|
||||
{
|
||||
/* Fluid motion blur already exported. */
|
||||
BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob);
|
||||
if (b_fluid_domain) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Cached motion blur already exported. */
|
||||
BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find(b_ob, true, nullptr);
|
||||
if (mesh_cache) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip if no vertices were exported. */
|
||||
size_t numverts = mesh->get_verts().size();
|
||||
if (numverts == 0) {
|
||||
@@ -1255,11 +1215,13 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
||||
/* Skip objects without deforming modifiers. this is not totally reliable,
|
||||
* would need a more extensive check to see which objects are animated. */
|
||||
BL::Mesh b_mesh(PointerRNA_NULL);
|
||||
if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
|
||||
if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
|
||||
/* get derived mesh */
|
||||
b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
|
||||
b_mesh = object_to_mesh(b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
|
||||
}
|
||||
|
||||
const std::string ob_name = b_ob_info.real_object.name();
|
||||
|
||||
/* TODO(sergey): Perform preliminary check for number of vertices. */
|
||||
if (b_mesh) {
|
||||
/* Export deformed coordinates. */
|
||||
@@ -1295,17 +1257,17 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
||||
memcmp(mP, &mesh->get_verts()[0], sizeof(float3) * numverts) == 0) {
|
||||
/* no motion, remove attributes again */
|
||||
if (b_mesh.vertices.length() != numverts) {
|
||||
VLOG(1) << "Topology differs, disabling motion blur for object " << b_ob.name();
|
||||
VLOG(1) << "Topology differs, disabling motion blur for object " << ob_name;
|
||||
}
|
||||
else {
|
||||
VLOG(1) << "No actual deformation motion for object " << b_ob.name();
|
||||
VLOG(1) << "No actual deformation motion for object " << ob_name;
|
||||
}
|
||||
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
if (attr_mN)
|
||||
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
|
||||
}
|
||||
else if (motion_step > 0) {
|
||||
VLOG(1) << "Filling deformation motion for object " << b_ob.name();
|
||||
VLOG(1) << "Filling deformation motion for object " << ob_name;
|
||||
/* motion, fill up previous steps that we might have skipped because
|
||||
* they had no motion, but we need them anyway now */
|
||||
float3 *P = &mesh->get_verts()[0];
|
||||
@@ -1319,8 +1281,8 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
||||
}
|
||||
else {
|
||||
if (b_mesh.vertices.length() != numverts) {
|
||||
VLOG(1) << "Topology differs, discarding motion blur for object " << b_ob.name()
|
||||
<< " at time " << motion_step;
|
||||
VLOG(1) << "Topology differs, discarding motion blur for object " << ob_name << " at time "
|
||||
<< motion_step;
|
||||
memcpy(mP, &mesh->get_verts()[0], sizeof(float3) * numverts);
|
||||
if (mN != NULL) {
|
||||
memcpy(mN, attr_N->data_float3(), sizeof(float3) * numverts);
|
||||
@@ -1328,7 +1290,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
||||
}
|
||||
}
|
||||
|
||||
free_object_to_mesh(b_data, b_ob, b_mesh);
|
||||
free_object_to_mesh(b_data, b_ob_info, b_mesh);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -154,7 +154,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
const bool is_instance = b_instance.is_instance();
|
||||
BL::Object b_ob = b_instance.object();
|
||||
BL::Object b_parent = is_instance ? b_instance.parent() : b_instance.object();
|
||||
BL::Object b_ob_instance = is_instance ? b_instance.instance_object() : b_ob;
|
||||
BObjectInfo b_ob_info{b_ob, is_instance ? b_instance.instance_object() : b_ob, b_ob.data()};
|
||||
const bool motion = motion_time != 0.0f;
|
||||
/*const*/ Transform tfm = get_transform(b_ob.matrix_world());
|
||||
int *persistent_id = NULL;
|
||||
@@ -178,8 +178,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
{
|
||||
sync_light(b_parent,
|
||||
persistent_id,
|
||||
b_ob,
|
||||
b_ob_instance,
|
||||
b_ob_info,
|
||||
is_instance ? b_instance.random_id() : 0,
|
||||
tfm,
|
||||
use_portal);
|
||||
@@ -231,7 +230,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
TaskPool *object_geom_task_pool = (is_instance) ? NULL : geom_task_pool;
|
||||
|
||||
/* key to lookup object */
|
||||
ObjectKey key(b_parent, persistent_id, b_ob_instance, use_particle_hair);
|
||||
ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, use_particle_hair);
|
||||
Object *object;
|
||||
|
||||
/* motion vector case */
|
||||
@@ -249,12 +248,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
|
||||
/* mesh deformation */
|
||||
if (object->get_geometry())
|
||||
sync_geometry_motion(b_depsgraph,
|
||||
b_ob_instance,
|
||||
object,
|
||||
motion_time,
|
||||
use_particle_hair,
|
||||
object_geom_task_pool);
|
||||
sync_geometry_motion(
|
||||
b_depsgraph, b_ob_info, object, motion_time, use_particle_hair, object_geom_task_pool);
|
||||
}
|
||||
|
||||
return object;
|
||||
@@ -265,15 +260,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
(tfm != object->get_tfm());
|
||||
|
||||
/* mesh sync */
|
||||
/* b_ob is owned by the iterator and will go out of scope at the end of the block.
|
||||
* b_ob_instance is the original object and will remain valid for deferred geometry
|
||||
* sync. */
|
||||
Geometry *geometry = sync_geometry(b_depsgraph,
|
||||
b_ob_instance,
|
||||
b_ob_instance,
|
||||
object_updated,
|
||||
use_particle_hair,
|
||||
object_geom_task_pool);
|
||||
Geometry *geometry = sync_geometry(
|
||||
b_depsgraph, b_ob_info, object_updated, use_particle_hair, object_geom_task_pool);
|
||||
object->set_geometry(geometry);
|
||||
|
||||
/* special case not tracked by object update flags */
|
||||
@@ -580,7 +568,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
||||
/* object loop */
|
||||
bool cancel = false;
|
||||
bool use_portal = false;
|
||||
const bool show_lights = BlenderViewportParameters(b_v3d).use_scene_lights;
|
||||
const bool show_lights = BlenderViewportParameters(b_v3d, use_developer_ui).use_scene_lights;
|
||||
|
||||
BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
|
||||
BL::Depsgraph::object_instances_iterator b_instance_iter;
|
||||
@@ -616,7 +604,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
||||
* only available in preview renders since currently do not have a good cache policy, the
|
||||
* data being loaded at once for all the frames. */
|
||||
if (experimental && b_v3d) {
|
||||
b_mesh_cache = object_mesh_cache_find(b_ob, false, &has_subdivision_modifier);
|
||||
b_mesh_cache = object_mesh_cache_find(b_ob, &has_subdivision_modifier);
|
||||
use_procedural = b_mesh_cache && b_mesh_cache.cache_file().use_render_procedural();
|
||||
}
|
||||
|
||||
@@ -731,6 +719,14 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
|
||||
}
|
||||
}
|
||||
|
||||
/* Check which geometry already has motion blur so it can be skipped. */
|
||||
geometry_motion_attribute_synced.clear();
|
||||
for (Geometry *geom : scene->geometry) {
|
||||
if (geom->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
|
||||
geometry_motion_attribute_synced.insert(geom);
|
||||
}
|
||||
}
|
||||
|
||||
/* note iteration over motion_times set happens in sorted order */
|
||||
foreach (float relative_time, motion_times) {
|
||||
/* center time is already handled. */
|
||||
@@ -761,6 +757,8 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
|
||||
sync_objects(b_depsgraph, b_v3d, relative_time);
|
||||
}
|
||||
|
||||
geometry_motion_attribute_synced.clear();
|
||||
|
||||
/* we need to set the python thread state again because this
|
||||
* function assumes it is being executed from python and will
|
||||
* try to save the thread state */
|
||||
|
@@ -45,10 +45,6 @@
|
||||
# include <OSL/oslquery.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_OPENCL
|
||||
# include "device/device_intern.h"
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
namespace {
|
||||
@@ -72,12 +68,10 @@ PyObject *pyunicode_from_string(const char *str)
|
||||
/* Synchronize debug flags from a given Blender scene.
|
||||
* Return truth when device list needs invalidation.
|
||||
*/
|
||||
bool debug_flags_sync_from_scene(BL::Scene b_scene)
|
||||
static void debug_flags_sync_from_scene(BL::Scene b_scene)
|
||||
{
|
||||
DebugFlagsRef flags = DebugFlags();
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
/* Backup some settings for comparison. */
|
||||
DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type;
|
||||
/* Synchronize shared flags. */
|
||||
flags.viewport_static_bvh = get_enum(cscene, "debug_bvh_type");
|
||||
/* Synchronize CPU flags. */
|
||||
@@ -87,50 +81,19 @@ bool debug_flags_sync_from_scene(BL::Scene b_scene)
|
||||
flags.cpu.sse3 = get_boolean(cscene, "debug_use_cpu_sse3");
|
||||
flags.cpu.sse2 = get_boolean(cscene, "debug_use_cpu_sse2");
|
||||
flags.cpu.bvh_layout = (BVHLayout)get_enum(cscene, "debug_bvh_layout");
|
||||
flags.cpu.split_kernel = get_boolean(cscene, "debug_use_cpu_split_kernel");
|
||||
/* Synchronize CUDA flags. */
|
||||
flags.cuda.adaptive_compile = get_boolean(cscene, "debug_use_cuda_adaptive_compile");
|
||||
flags.cuda.split_kernel = get_boolean(cscene, "debug_use_cuda_split_kernel");
|
||||
/* Synchronize OptiX flags. */
|
||||
flags.optix.cuda_streams = get_int(cscene, "debug_optix_cuda_streams");
|
||||
flags.optix.curves_api = get_boolean(cscene, "debug_optix_curves_api");
|
||||
/* Synchronize OpenCL device type. */
|
||||
switch (get_enum(cscene, "debug_opencl_device_type")) {
|
||||
case 0:
|
||||
flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE;
|
||||
break;
|
||||
case 1:
|
||||
flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_ALL;
|
||||
break;
|
||||
case 2:
|
||||
flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_DEFAULT;
|
||||
break;
|
||||
case 3:
|
||||
flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_CPU;
|
||||
break;
|
||||
case 4:
|
||||
flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_GPU;
|
||||
break;
|
||||
case 5:
|
||||
flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_ACCELERATOR;
|
||||
break;
|
||||
}
|
||||
/* Synchronize other OpenCL flags. */
|
||||
flags.opencl.debug = get_boolean(cscene, "debug_use_opencl_debug");
|
||||
flags.opencl.mem_limit = ((size_t)get_int(cscene, "debug_opencl_mem_limit")) * 1024 * 1024;
|
||||
return flags.opencl.device_type != opencl_device_type;
|
||||
flags.optix.use_debug = get_boolean(cscene, "debug_use_optix_debug");
|
||||
}
|
||||
|
||||
/* Reset debug flags to default values.
|
||||
* Return truth when device list needs invalidation.
|
||||
*/
|
||||
bool debug_flags_reset()
|
||||
static void debug_flags_reset()
|
||||
{
|
||||
DebugFlagsRef flags = DebugFlags();
|
||||
/* Backup some settings for comparison. */
|
||||
DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type;
|
||||
flags.reset();
|
||||
return flags.opencl.device_type != opencl_device_type;
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
@@ -175,18 +138,20 @@ static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
|
||||
|
||||
static PyObject *init_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
PyObject *path, *user_path;
|
||||
PyObject *path, *user_path, *temp_path;
|
||||
int headless;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "OOi", &path, &user_path, &headless)) {
|
||||
return NULL;
|
||||
if (!PyArg_ParseTuple(args, "OOOi", &path, &user_path, &temp_path, &headless)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PyObject *path_coerce = NULL, *user_path_coerce = NULL;
|
||||
PyObject *path_coerce = nullptr, *user_path_coerce = nullptr, *temp_path_coerce = nullptr;
|
||||
path_init(PyC_UnicodeAsByte(path, &path_coerce),
|
||||
PyC_UnicodeAsByte(user_path, &user_path_coerce));
|
||||
PyC_UnicodeAsByte(user_path, &user_path_coerce),
|
||||
PyC_UnicodeAsByte(temp_path, &temp_path_coerce));
|
||||
Py_XDECREF(path_coerce);
|
||||
Py_XDECREF(user_path_coerce);
|
||||
Py_XDECREF(temp_path_coerce);
|
||||
|
||||
BlenderSession::headless = headless;
|
||||
|
||||
@@ -299,6 +264,50 @@ static PyObject *render_func(PyObject * /*self*/, PyObject *args)
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *render_frame_finish_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
PyObject *pysession;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O", &pysession)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
|
||||
|
||||
/* Allow Blender to execute other Python scripts. */
|
||||
python_thread_state_save(&session->python_thread_state);
|
||||
|
||||
session->render_frame_finish();
|
||||
|
||||
python_thread_state_restore(&session->python_thread_state);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
PyObject *py_session, *py_graph, *py_screen, *py_space_image;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "OOOO", &py_session, &py_graph, &py_screen, &py_space_image)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(py_session);
|
||||
|
||||
ID *b_screen = (ID *)PyLong_AsVoidPtr(py_screen);
|
||||
|
||||
PointerRNA b_space_image_ptr;
|
||||
RNA_pointer_create(b_screen,
|
||||
&RNA_SpaceImageEditor,
|
||||
pylong_as_voidptr_typesafe(py_space_image),
|
||||
&b_space_image_ptr);
|
||||
BL::SpaceImageEditor b_space_image(b_space_image_ptr);
|
||||
|
||||
session->draw(b_space_image);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/* pixel_array and result passed as pointers */
|
||||
static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
@@ -336,7 +345,7 @@ static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
|
||||
static PyObject *view_draw_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
PyObject *pysession, *pygraph, *pyv3d, *pyrv3d;
|
||||
|
||||
@@ -350,7 +359,7 @@ static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
|
||||
int viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
|
||||
session->draw(viewport[2], viewport[3]);
|
||||
session->view_draw(viewport[2], viewport[3]);
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
@@ -697,40 +706,6 @@ static PyObject *system_info_func(PyObject * /*self*/, PyObject * /*value*/)
|
||||
return pyunicode_from_string(system_info.c_str());
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENCL
|
||||
static PyObject *opencl_disable_func(PyObject * /*self*/, PyObject * /*value*/)
|
||||
{
|
||||
VLOG(2) << "Disabling OpenCL platform.";
|
||||
DebugFlags().opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *opencl_compile_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
PyObject *sequence = PySequence_Fast(args, "Arguments must be a sequence");
|
||||
if (sequence == NULL) {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
vector<string> parameters;
|
||||
for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(sequence); i++) {
|
||||
PyObject *item = PySequence_Fast_GET_ITEM(sequence, i);
|
||||
PyObject *item_as_string = PyObject_Str(item);
|
||||
const char *parameter_string = PyUnicode_AsUTF8(item_as_string);
|
||||
parameters.push_back(parameter_string);
|
||||
Py_DECREF(item_as_string);
|
||||
}
|
||||
Py_DECREF(sequence);
|
||||
|
||||
if (device_opencl_compile_kernel(parameters)) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
else {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool image_parse_filepaths(PyObject *pyfilepaths, vector<string> &filepaths)
|
||||
{
|
||||
if (PyUnicode_Check(pyfilepaths)) {
|
||||
@@ -762,6 +737,10 @@ static bool image_parse_filepaths(PyObject *pyfilepaths, vector<string> &filepat
|
||||
|
||||
static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
|
||||
{
|
||||
#if 1
|
||||
(void)args;
|
||||
(void)keywords;
|
||||
#else
|
||||
static const char *keyword_list[] = {
|
||||
"preferences", "scene", "view_layer", "input", "output", "tile_size", "samples", NULL};
|
||||
PyObject *pypreferences, *pyscene, *pyviewlayer;
|
||||
@@ -835,7 +814,7 @@ static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *key
|
||||
}
|
||||
|
||||
/* Create denoiser. */
|
||||
Denoiser denoiser(device);
|
||||
DenoiserPipeline denoiser(device);
|
||||
denoiser.params = params;
|
||||
denoiser.input = input;
|
||||
denoiser.output = output;
|
||||
@@ -852,6 +831,7 @@ static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *key
|
||||
PyErr_SetString(PyExc_ValueError, denoiser.error.c_str());
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
@@ -903,10 +883,7 @@ static PyObject *debug_flags_update_func(PyObject * /*self*/, PyObject *args)
|
||||
RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyscene), &sceneptr);
|
||||
BL::Scene b_scene(sceneptr);
|
||||
|
||||
if (debug_flags_sync_from_scene(b_scene)) {
|
||||
VLOG(2) << "Tagging device list for update.";
|
||||
Device::tag_update();
|
||||
}
|
||||
debug_flags_sync_from_scene(b_scene);
|
||||
|
||||
VLOG(2) << "Debug flags set to:\n" << DebugFlags();
|
||||
|
||||
@@ -917,10 +894,7 @@ static PyObject *debug_flags_update_func(PyObject * /*self*/, PyObject *args)
|
||||
|
||||
static PyObject *debug_flags_reset_func(PyObject * /*self*/, PyObject * /*args*/)
|
||||
{
|
||||
if (debug_flags_reset()) {
|
||||
VLOG(2) << "Tagging device list for update.";
|
||||
Device::tag_update();
|
||||
}
|
||||
debug_flags_reset();
|
||||
if (debug_flags_set) {
|
||||
VLOG(2) << "Debug flags reset to:\n" << DebugFlags();
|
||||
debug_flags_set = false;
|
||||
@@ -928,84 +902,6 @@ static PyObject *debug_flags_reset_func(PyObject * /*self*/, PyObject * /*args*/
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *set_resumable_chunk_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
int num_resumable_chunks, current_resumable_chunk;
|
||||
if (!PyArg_ParseTuple(args, "ii", &num_resumable_chunks, ¤t_resumable_chunk)) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
if (num_resumable_chunks <= 0) {
|
||||
fprintf(stderr, "Cycles: Bad value for number of resumable chunks.\n");
|
||||
abort();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
if (current_resumable_chunk < 1 || current_resumable_chunk > num_resumable_chunks) {
|
||||
fprintf(stderr, "Cycles: Bad value for current resumable chunk number.\n");
|
||||
abort();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
VLOG(1) << "Initialized resumable render: "
|
||||
<< "num_resumable_chunks=" << num_resumable_chunks << ", "
|
||||
<< "current_resumable_chunk=" << current_resumable_chunk;
|
||||
BlenderSession::num_resumable_chunks = num_resumable_chunks;
|
||||
BlenderSession::current_resumable_chunk = current_resumable_chunk;
|
||||
|
||||
printf("Cycles: Will render chunk %d of %d\n", current_resumable_chunk, num_resumable_chunks);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *set_resumable_chunk_range_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
int num_chunks, start_chunk, end_chunk;
|
||||
if (!PyArg_ParseTuple(args, "iii", &num_chunks, &start_chunk, &end_chunk)) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
if (num_chunks <= 0) {
|
||||
fprintf(stderr, "Cycles: Bad value for number of resumable chunks.\n");
|
||||
abort();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
if (start_chunk < 1 || start_chunk > num_chunks) {
|
||||
fprintf(stderr, "Cycles: Bad value for start chunk number.\n");
|
||||
abort();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
if (end_chunk < 1 || end_chunk > num_chunks) {
|
||||
fprintf(stderr, "Cycles: Bad value for start chunk number.\n");
|
||||
abort();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
if (start_chunk > end_chunk) {
|
||||
fprintf(stderr, "Cycles: End chunk should be higher than start one.\n");
|
||||
abort();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
VLOG(1) << "Initialized resumable render: "
|
||||
<< "num_resumable_chunks=" << num_chunks << ", "
|
||||
<< "start_resumable_chunk=" << start_chunk << "end_resumable_chunk=" << end_chunk;
|
||||
BlenderSession::num_resumable_chunks = num_chunks;
|
||||
BlenderSession::start_resumable_chunk = start_chunk;
|
||||
BlenderSession::end_resumable_chunk = end_chunk;
|
||||
|
||||
printf("Cycles: Will render chunks %d to %d of %d\n", start_chunk, end_chunk, num_chunks);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *clear_resumable_chunk_func(PyObject * /*self*/, PyObject * /*value*/)
|
||||
{
|
||||
VLOG(1) << "Clear resumable render";
|
||||
BlenderSession::num_resumable_chunks = 0;
|
||||
BlenderSession::current_resumable_chunk = 0;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*/)
|
||||
{
|
||||
BlenderSession::print_render_stats = true;
|
||||
@@ -1015,16 +911,14 @@ static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*
|
||||
static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
|
||||
{
|
||||
vector<DeviceType> device_types = Device::available_types();
|
||||
bool has_cuda = false, has_optix = false, has_opencl = false;
|
||||
bool has_cuda = false, has_optix = false;
|
||||
foreach (DeviceType device_type, device_types) {
|
||||
has_cuda |= (device_type == DEVICE_CUDA);
|
||||
has_optix |= (device_type == DEVICE_OPTIX);
|
||||
has_opencl |= (device_type == DEVICE_OPENCL);
|
||||
}
|
||||
PyObject *list = PyTuple_New(3);
|
||||
PyObject *list = PyTuple_New(2);
|
||||
PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
|
||||
PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_optix));
|
||||
PyTuple_SET_ITEM(list, 2, PyBool_FromLong(has_opencl));
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -1044,9 +938,6 @@ static PyObject *set_device_override_func(PyObject * /*self*/, PyObject *arg)
|
||||
if (override == "CPU") {
|
||||
BlenderSession::device_override = DEVICE_MASK_CPU;
|
||||
}
|
||||
else if (override == "OPENCL") {
|
||||
BlenderSession::device_override = DEVICE_MASK_OPENCL;
|
||||
}
|
||||
else if (override == "CUDA") {
|
||||
BlenderSession::device_override = DEVICE_MASK_CUDA;
|
||||
}
|
||||
@@ -1072,8 +963,10 @@ static PyMethodDef methods[] = {
|
||||
{"create", create_func, METH_VARARGS, ""},
|
||||
{"free", free_func, METH_O, ""},
|
||||
{"render", render_func, METH_VARARGS, ""},
|
||||
{"bake", bake_func, METH_VARARGS, ""},
|
||||
{"render_frame_finish", render_frame_finish_func, METH_VARARGS, ""},
|
||||
{"draw", draw_func, METH_VARARGS, ""},
|
||||
{"bake", bake_func, METH_VARARGS, ""},
|
||||
{"view_draw", view_draw_func, METH_VARARGS, ""},
|
||||
{"sync", sync_func, METH_VARARGS, ""},
|
||||
{"reset", reset_func, METH_VARARGS, ""},
|
||||
#ifdef WITH_OSL
|
||||
@@ -1082,10 +975,6 @@ static PyMethodDef methods[] = {
|
||||
#endif
|
||||
{"available_devices", available_devices_func, METH_VARARGS, ""},
|
||||
{"system_info", system_info_func, METH_NOARGS, ""},
|
||||
#ifdef WITH_OPENCL
|
||||
{"opencl_disable", opencl_disable_func, METH_NOARGS, ""},
|
||||
{"opencl_compile", opencl_compile_func, METH_VARARGS, ""},
|
||||
#endif
|
||||
|
||||
/* Standalone denoising */
|
||||
{"denoise", (PyCFunction)denoise_func, METH_VARARGS | METH_KEYWORDS, ""},
|
||||
@@ -1098,11 +987,6 @@ static PyMethodDef methods[] = {
|
||||
/* Statistics. */
|
||||
{"enable_print_stats", enable_print_stats_func, METH_NOARGS, ""},
|
||||
|
||||
/* Resumable render */
|
||||
{"set_resumable_chunk", set_resumable_chunk_func, METH_VARARGS, ""},
|
||||
{"set_resumable_chunk_range", set_resumable_chunk_range_func, METH_VARARGS, ""},
|
||||
{"clear_resumable_chunk", clear_resumable_chunk_func, METH_NOARGS, ""},
|
||||
|
||||
/* Compute Device selection */
|
||||
{"get_device_types", get_device_types_func, METH_VARARGS, ""},
|
||||
{"set_device_override", set_device_override_func, METH_O, ""},
|
||||
@@ -1153,14 +1037,6 @@ void *CCL_python_module_init()
|
||||
PyModule_AddStringConstant(mod, "osl_version_string", "unknown");
|
||||
#endif
|
||||
|
||||
#ifdef WITH_NETWORK
|
||||
PyModule_AddObject(mod, "with_network", Py_True);
|
||||
Py_INCREF(Py_True);
|
||||
#else /* WITH_NETWORK */
|
||||
PyModule_AddObject(mod, "with_network", Py_False);
|
||||
Py_INCREF(Py_False);
|
||||
#endif /* WITH_NETWORK */
|
||||
|
||||
#ifdef WITH_EMBREE
|
||||
PyModule_AddObject(mod, "with_embree", Py_True);
|
||||
Py_INCREF(Py_True);
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -29,12 +29,11 @@
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class BlenderGPUDisplay;
|
||||
class BlenderSync;
|
||||
class ImageMetaData;
|
||||
class Scene;
|
||||
class Session;
|
||||
class RenderBuffers;
|
||||
class RenderTile;
|
||||
|
||||
class BlenderSession {
|
||||
public:
|
||||
@@ -62,6 +61,8 @@ class BlenderSession {
|
||||
/* offline render */
|
||||
void render(BL::Depsgraph &b_depsgraph);
|
||||
|
||||
void render_frame_finish();
|
||||
|
||||
void bake(BL::Depsgraph &b_depsgrah,
|
||||
BL::Object &b_object,
|
||||
const string &pass_type,
|
||||
@@ -69,24 +70,29 @@ class BlenderSession {
|
||||
const int bake_width,
|
||||
const int bake_height);
|
||||
|
||||
void write_render_result(BL::RenderLayer &b_rlay, RenderTile &rtile);
|
||||
void write_render_tile(RenderTile &rtile);
|
||||
void read_render_tile(RenderTile &rtile);
|
||||
void write_render_result(BL::RenderLayer &b_rlay);
|
||||
void write_render_tile();
|
||||
|
||||
void update_render_tile();
|
||||
|
||||
void full_buffer_written(string_view filename);
|
||||
|
||||
/* update functions are used to update display buffer only after sample was rendered
|
||||
* only needed for better visual feedback */
|
||||
void update_render_result(BL::RenderLayer &b_rlay, RenderTile &rtile);
|
||||
void update_render_tile(RenderTile &rtile, bool highlight);
|
||||
void update_render_result(BL::RenderLayer &b_rlay);
|
||||
|
||||
/* read functions for baking input */
|
||||
void read_render_tile();
|
||||
|
||||
/* interactive updates */
|
||||
void synchronize(BL::Depsgraph &b_depsgraph);
|
||||
|
||||
/* drawing */
|
||||
bool draw(int w, int h);
|
||||
void draw(BL::SpaceImageEditor &space_image);
|
||||
void view_draw(int w, int h);
|
||||
void tag_redraw();
|
||||
void tag_update();
|
||||
void get_status(string &status, string &substatus);
|
||||
void get_kernel_status(string &kernel_status);
|
||||
void get_progress(float &progress, double &total_time, double &render_time);
|
||||
void test_cancel();
|
||||
void update_status_progress();
|
||||
@@ -123,6 +129,8 @@ class BlenderSession {
|
||||
|
||||
void *python_thread_state;
|
||||
|
||||
bool use_developer_ui;
|
||||
|
||||
/* Global state which is common for all render sessions created from Blender.
|
||||
* Usually denotes command line arguments.
|
||||
*/
|
||||
@@ -134,41 +142,28 @@ class BlenderSession {
|
||||
*/
|
||||
static bool headless;
|
||||
|
||||
/* ** Resumable render ** */
|
||||
|
||||
/* Overall number of chunks in which the sample range is to be divided. */
|
||||
static int num_resumable_chunks;
|
||||
|
||||
/* Current resumable chunk index to render. */
|
||||
static int current_resumable_chunk;
|
||||
|
||||
/* Alternative to single-chunk rendering to render a range of chunks. */
|
||||
static int start_resumable_chunk;
|
||||
static int end_resumable_chunk;
|
||||
|
||||
static bool print_render_stats;
|
||||
|
||||
protected:
|
||||
void stamp_view_layer_metadata(Scene *scene, const string &view_layer_name);
|
||||
|
||||
void do_write_update_render_result(BL::RenderLayer &b_rlay,
|
||||
RenderTile &rtile,
|
||||
bool do_update_only);
|
||||
void do_write_update_render_tile(RenderTile &rtile,
|
||||
bool do_update_only,
|
||||
bool do_read_only,
|
||||
bool highlight);
|
||||
|
||||
void builtin_images_load();
|
||||
|
||||
/* Update tile manager to reflect resumable render settings. */
|
||||
void update_resumable_tile_manager(int num_samples);
|
||||
|
||||
/* Is used after each render layer synchronization is done with the goal
|
||||
* of freeing render engine data which is held from Blender side (for
|
||||
* example, dependency graph).
|
||||
*/
|
||||
void free_blender_memory_if_possible();
|
||||
|
||||
struct {
|
||||
thread_mutex mutex;
|
||||
int last_pass_index = -1;
|
||||
} draw_state_;
|
||||
|
||||
/* NOTE: The BlenderSession references the GPU display. */
|
||||
BlenderGPUDisplay *gpu_display_ = nullptr;
|
||||
|
||||
vector<string> full_buffer_files_;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include "render/background.h"
|
||||
#include "render/colorspace.h"
|
||||
#include "render/graph.h"
|
||||
#include "render/integrator.h"
|
||||
#include "render/light.h"
|
||||
#include "render/nodes.h"
|
||||
#include "render/osl.h"
|
||||
@@ -475,17 +476,11 @@ static ShaderNode *add_node(Scene *scene,
|
||||
SubsurfaceScatteringNode *subsurface = graph->create_node<SubsurfaceScatteringNode>();
|
||||
|
||||
switch (b_subsurface_node.falloff()) {
|
||||
case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC:
|
||||
subsurface->set_falloff(CLOSURE_BSSRDF_CUBIC_ID);
|
||||
break;
|
||||
case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN:
|
||||
subsurface->set_falloff(CLOSURE_BSSRDF_GAUSSIAN_ID);
|
||||
break;
|
||||
case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY:
|
||||
subsurface->set_falloff(CLOSURE_BSSRDF_BURLEY_ID);
|
||||
case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK_FIXED_RADIUS:
|
||||
subsurface->set_method(CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
|
||||
break;
|
||||
case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK:
|
||||
subsurface->set_falloff(CLOSURE_BSSRDF_RANDOM_WALK_ID);
|
||||
subsurface->set_method(CLOSURE_BSSRDF_RANDOM_WALK_ID);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -597,11 +592,11 @@ static ShaderNode *add_node(Scene *scene,
|
||||
break;
|
||||
}
|
||||
switch (b_principled_node.subsurface_method()) {
|
||||
case BL::ShaderNodeBsdfPrincipled::subsurface_method_BURLEY:
|
||||
principled->set_subsurface_method(CLOSURE_BSSRDF_PRINCIPLED_ID);
|
||||
case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK_FIXED_RADIUS:
|
||||
principled->set_subsurface_method(CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
|
||||
break;
|
||||
case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK:
|
||||
principled->set_subsurface_method(CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID);
|
||||
principled->set_subsurface_method(CLOSURE_BSSRDF_RANDOM_WALK_ID);
|
||||
break;
|
||||
}
|
||||
node = principled;
|
||||
@@ -1360,10 +1355,11 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
|
||||
void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all)
|
||||
{
|
||||
Background *background = scene->background;
|
||||
Integrator *integrator = scene->integrator;
|
||||
|
||||
BL::World b_world = b_scene.world();
|
||||
|
||||
BlenderViewportParameters new_viewport_parameters(b_v3d);
|
||||
BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui);
|
||||
|
||||
if (world_recalc || update_all || b_world.ptr.data != world_map ||
|
||||
viewport_parameters.shader_modified(new_viewport_parameters)) {
|
||||
@@ -1455,9 +1451,8 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
|
||||
/* AO */
|
||||
BL::WorldLighting b_light = b_world.light_settings();
|
||||
|
||||
background->set_use_ao(b_light.use_ambient_occlusion());
|
||||
background->set_ao_factor(b_light.ao_factor());
|
||||
background->set_ao_distance(b_light.distance());
|
||||
integrator->set_ao_factor(b_light.ao_factor());
|
||||
integrator->set_ao_distance(b_light.distance());
|
||||
|
||||
/* visibility */
|
||||
PointerRNA cvisibility = RNA_pointer_get(&b_world.ptr, "cycles_visibility");
|
||||
@@ -1472,9 +1467,8 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
|
||||
background->set_visibility(visibility);
|
||||
}
|
||||
else {
|
||||
background->set_use_ao(false);
|
||||
background->set_ao_factor(0.0f);
|
||||
background->set_ao_distance(FLT_MAX);
|
||||
integrator->set_ao_factor(1.0f);
|
||||
integrator->set_ao_distance(10.0f);
|
||||
}
|
||||
|
||||
shader->set_graph(graph);
|
||||
@@ -1496,7 +1490,6 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
|
||||
|
||||
background->set_use_shader(view_layer.use_background_shader ||
|
||||
viewport_parameters.use_custom_shader());
|
||||
background->set_use_ao(background->get_use_ao() && view_layer.use_background_ao);
|
||||
|
||||
background->tag_update(scene);
|
||||
}
|
||||
|
@@ -53,6 +53,7 @@ BlenderSync::BlenderSync(BL::RenderEngine &b_engine,
|
||||
BL::Scene &b_scene,
|
||||
Scene *scene,
|
||||
bool preview,
|
||||
bool use_developer_ui,
|
||||
Progress &progress)
|
||||
: b_engine(b_engine),
|
||||
b_data(b_data),
|
||||
@@ -68,6 +69,7 @@ BlenderSync::BlenderSync(BL::RenderEngine &b_engine,
|
||||
scene(scene),
|
||||
preview(preview),
|
||||
experimental(false),
|
||||
use_developer_ui(use_developer_ui),
|
||||
dicing_rate(1.0f),
|
||||
max_subdivisions(12),
|
||||
progress(progress),
|
||||
@@ -224,7 +226,7 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
|
||||
}
|
||||
|
||||
if (b_v3d) {
|
||||
BlenderViewportParameters new_viewport_parameters(b_v3d);
|
||||
BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui);
|
||||
|
||||
if (viewport_parameters.shader_modified(new_viewport_parameters)) {
|
||||
world_recalc = true;
|
||||
@@ -251,9 +253,13 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render,
|
||||
|
||||
BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
|
||||
|
||||
/* TODO(sergey): This feels weak to pass view layer to the integrator, and even weaker to have an
|
||||
* implicit check on whether it is a background render or not. What is the nicer thing here? */
|
||||
const bool background = !b_v3d;
|
||||
|
||||
sync_view_layer(b_view_layer);
|
||||
sync_integrator();
|
||||
sync_film(b_v3d);
|
||||
sync_integrator(b_view_layer, background);
|
||||
sync_film(b_view_layer, b_v3d);
|
||||
sync_shaders(b_depsgraph, b_v3d);
|
||||
sync_images();
|
||||
|
||||
@@ -280,7 +286,7 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render,
|
||||
|
||||
/* Integrator */
|
||||
|
||||
void BlenderSync::sync_integrator()
|
||||
void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
|
||||
{
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
|
||||
@@ -328,59 +334,24 @@ void BlenderSync::sync_integrator()
|
||||
integrator->set_motion_blur(view_layer.use_motion_blur);
|
||||
}
|
||||
|
||||
integrator->set_method((Integrator::Method)get_enum(
|
||||
cscene, "progressive", Integrator::NUM_METHODS, Integrator::PATH));
|
||||
|
||||
integrator->set_sample_all_lights_direct(get_boolean(cscene, "sample_all_lights_direct"));
|
||||
integrator->set_sample_all_lights_indirect(get_boolean(cscene, "sample_all_lights_indirect"));
|
||||
integrator->set_light_sampling_threshold(get_float(cscene, "light_sampling_threshold"));
|
||||
|
||||
SamplingPattern sampling_pattern = (SamplingPattern)get_enum(
|
||||
cscene, "sampling_pattern", SAMPLING_NUM_PATTERNS, SAMPLING_PATTERN_SOBOL);
|
||||
|
||||
int adaptive_min_samples = INT_MAX;
|
||||
|
||||
if (RNA_boolean_get(&cscene, "use_adaptive_sampling")) {
|
||||
sampling_pattern = SAMPLING_PATTERN_PMJ;
|
||||
adaptive_min_samples = get_int(cscene, "adaptive_min_samples");
|
||||
integrator->set_adaptive_threshold(get_float(cscene, "adaptive_threshold"));
|
||||
}
|
||||
else {
|
||||
integrator->set_adaptive_threshold(0.0f);
|
||||
}
|
||||
|
||||
integrator->set_sampling_pattern(sampling_pattern);
|
||||
|
||||
int diffuse_samples = get_int(cscene, "diffuse_samples");
|
||||
int glossy_samples = get_int(cscene, "glossy_samples");
|
||||
int transmission_samples = get_int(cscene, "transmission_samples");
|
||||
int ao_samples = get_int(cscene, "ao_samples");
|
||||
int mesh_light_samples = get_int(cscene, "mesh_light_samples");
|
||||
int subsurface_samples = get_int(cscene, "subsurface_samples");
|
||||
int volume_samples = get_int(cscene, "volume_samples");
|
||||
|
||||
if (get_boolean(cscene, "use_square_samples")) {
|
||||
integrator->set_diffuse_samples(diffuse_samples * diffuse_samples);
|
||||
integrator->set_glossy_samples(glossy_samples * glossy_samples);
|
||||
integrator->set_transmission_samples(transmission_samples * transmission_samples);
|
||||
integrator->set_ao_samples(ao_samples * ao_samples);
|
||||
integrator->set_mesh_light_samples(mesh_light_samples * mesh_light_samples);
|
||||
integrator->set_subsurface_samples(subsurface_samples * subsurface_samples);
|
||||
integrator->set_volume_samples(volume_samples * volume_samples);
|
||||
adaptive_min_samples = min(adaptive_min_samples * adaptive_min_samples, INT_MAX);
|
||||
if (preview) {
|
||||
integrator->set_use_adaptive_sampling(
|
||||
RNA_boolean_get(&cscene, "use_preview_adaptive_sampling"));
|
||||
integrator->set_adaptive_threshold(get_float(cscene, "preview_adaptive_threshold"));
|
||||
integrator->set_adaptive_min_samples(get_int(cscene, "preview_adaptive_min_samples"));
|
||||
}
|
||||
else {
|
||||
integrator->set_diffuse_samples(diffuse_samples);
|
||||
integrator->set_glossy_samples(glossy_samples);
|
||||
integrator->set_transmission_samples(transmission_samples);
|
||||
integrator->set_ao_samples(ao_samples);
|
||||
integrator->set_mesh_light_samples(mesh_light_samples);
|
||||
integrator->set_subsurface_samples(subsurface_samples);
|
||||
integrator->set_volume_samples(volume_samples);
|
||||
integrator->set_use_adaptive_sampling(RNA_boolean_get(&cscene, "use_adaptive_sampling"));
|
||||
integrator->set_adaptive_threshold(get_float(cscene, "adaptive_threshold"));
|
||||
integrator->set_adaptive_min_samples(get_int(cscene, "adaptive_min_samples"));
|
||||
}
|
||||
|
||||
integrator->set_adaptive_min_samples(adaptive_min_samples);
|
||||
|
||||
if (get_boolean(cscene, "use_fast_gi")) {
|
||||
if (preview) {
|
||||
integrator->set_ao_bounces(get_int(cscene, "ao_bounces"));
|
||||
@@ -393,20 +364,38 @@ void BlenderSync::sync_integrator()
|
||||
integrator->set_ao_bounces(0);
|
||||
}
|
||||
|
||||
/* UPDATE_NONE as we don't want to tag the integrator as modified, just tag dependent things */
|
||||
const DenoiseParams denoise_params = get_denoise_params(b_scene, b_view_layer, background);
|
||||
integrator->set_use_denoise(denoise_params.use);
|
||||
|
||||
/* Only update denoiser parameters if the denoiser is actually used. This allows to tweak
|
||||
* denoiser parameters before enabling it without render resetting on every change. The downside
|
||||
* is that the interface and the integrator are technically out of sync. */
|
||||
if (denoise_params.use) {
|
||||
integrator->set_denoiser_type(denoise_params.type);
|
||||
integrator->set_denoise_start_sample(denoise_params.start_sample);
|
||||
integrator->set_use_denoise_pass_albedo(denoise_params.use_pass_albedo);
|
||||
integrator->set_use_denoise_pass_normal(denoise_params.use_pass_normal);
|
||||
integrator->set_denoiser_prefilter(denoise_params.prefilter);
|
||||
}
|
||||
|
||||
/* UPDATE_NONE as we don't want to tag the integrator as modified (this was done by the
|
||||
* set calls above), but we need to make sure that the dependent things are tagged. */
|
||||
integrator->tag_update(scene, Integrator::UPDATE_NONE);
|
||||
}
|
||||
|
||||
/* Film */
|
||||
|
||||
void BlenderSync::sync_film(BL::SpaceView3D &b_v3d)
|
||||
void BlenderSync::sync_film(BL::ViewLayer &b_view_layer, BL::SpaceView3D &b_v3d)
|
||||
{
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
|
||||
|
||||
Film *film = scene->film;
|
||||
|
||||
if (b_v3d) {
|
||||
film->set_display_pass(update_viewport_display_passes(b_v3d, scene->passes));
|
||||
const BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui);
|
||||
film->set_display_pass(new_viewport_parameters.display_pass);
|
||||
film->set_show_active_pixels(new_viewport_parameters.show_active_pixels);
|
||||
}
|
||||
|
||||
film->set_exposure(get_float(cscene, "film_exposure"));
|
||||
@@ -434,6 +423,15 @@ void BlenderSync::sync_film(BL::SpaceView3D &b_v3d)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Blender viewport does not support proper shadow catcher compositing, so force an approximate
|
||||
* mode to improve visual feedback. */
|
||||
if (b_v3d) {
|
||||
film->set_use_approximate_shadow_catcher(true);
|
||||
}
|
||||
else {
|
||||
film->set_use_approximate_shadow_catcher(!get_boolean(crl, "use_pass_shadow_catcher"));
|
||||
}
|
||||
}
|
||||
|
||||
/* Render Layer */
|
||||
@@ -444,7 +442,6 @@ void BlenderSync::sync_view_layer(BL::ViewLayer &b_view_layer)
|
||||
|
||||
/* Filter. */
|
||||
view_layer.use_background_shader = b_view_layer.use_sky();
|
||||
view_layer.use_background_ao = b_view_layer.use_ao();
|
||||
/* Always enable surfaces for baking, otherwise there is nothing to bake to. */
|
||||
view_layer.use_surfaces = b_view_layer.use_solid() || scene->bake_manager->get_baking();
|
||||
view_layer.use_hair = b_view_layer.use_strand();
|
||||
@@ -464,10 +461,7 @@ void BlenderSync::sync_view_layer(BL::ViewLayer &b_view_layer)
|
||||
|
||||
if (use_layer_samples != 2) {
|
||||
int samples = b_view_layer.samples();
|
||||
if (get_boolean(cscene, "use_square_samples"))
|
||||
view_layer.samples = samples * samples;
|
||||
else
|
||||
view_layer.samples = samples;
|
||||
view_layer.samples = samples;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,7 +493,8 @@ void BlenderSync::sync_images()
|
||||
}
|
||||
|
||||
/* Passes */
|
||||
PassType BlenderSync::get_pass_type(BL::RenderPass &b_pass)
|
||||
|
||||
static PassType get_blender_pass_type(BL::RenderPass &b_pass)
|
||||
{
|
||||
string name = b_pass.name();
|
||||
#define MAP_PASS(passname, passtype) \
|
||||
@@ -507,10 +502,15 @@ PassType BlenderSync::get_pass_type(BL::RenderPass &b_pass)
|
||||
return passtype; \
|
||||
} \
|
||||
((void)0)
|
||||
|
||||
/* NOTE: Keep in sync with defined names from DNA_scene_types.h */
|
||||
|
||||
MAP_PASS("Combined", PASS_COMBINED);
|
||||
MAP_PASS("Noisy Image", PASS_COMBINED);
|
||||
|
||||
MAP_PASS("Depth", PASS_DEPTH);
|
||||
MAP_PASS("Mist", PASS_MIST);
|
||||
MAP_PASS("Position", PASS_POSITION);
|
||||
MAP_PASS("Normal", PASS_NORMAL);
|
||||
MAP_PASS("IndexOB", PASS_OBJECT_ID);
|
||||
MAP_PASS("UV", PASS_UV);
|
||||
@@ -539,118 +539,92 @@ PassType BlenderSync::get_pass_type(BL::RenderPass &b_pass)
|
||||
MAP_PASS("BakePrimitive", PASS_BAKE_PRIMITIVE);
|
||||
MAP_PASS("BakeDifferential", PASS_BAKE_DIFFERENTIAL);
|
||||
|
||||
MAP_PASS("Denoising Normal", PASS_DENOISING_NORMAL);
|
||||
MAP_PASS("Denoising Albedo", PASS_DENOISING_ALBEDO);
|
||||
|
||||
MAP_PASS("Shadow Catcher", PASS_SHADOW_CATCHER);
|
||||
MAP_PASS("Noisy Shadow Catcher", PASS_SHADOW_CATCHER);
|
||||
|
||||
MAP_PASS("Debug Render Time", PASS_RENDER_TIME);
|
||||
|
||||
MAP_PASS("AdaptiveAuxBuffer", PASS_ADAPTIVE_AUX_BUFFER);
|
||||
MAP_PASS("Debug Sample Count", PASS_SAMPLE_COUNT);
|
||||
|
||||
if (string_startswith(name, cryptomatte_prefix)) {
|
||||
return PASS_CRYPTOMATTE;
|
||||
}
|
||||
|
||||
#undef MAP_PASS
|
||||
|
||||
return PASS_NONE;
|
||||
}
|
||||
|
||||
int BlenderSync::get_denoising_pass(BL::RenderPass &b_pass)
|
||||
static Pass *pass_add(Scene *scene,
|
||||
PassType type,
|
||||
const char *name,
|
||||
PassMode mode = PassMode::DENOISED)
|
||||
{
|
||||
string name = b_pass.name();
|
||||
Pass *pass = scene->create_node<Pass>();
|
||||
|
||||
if (name == "Noisy Image")
|
||||
return DENOISING_PASS_PREFILTERED_COLOR;
|
||||
pass->set_type(type);
|
||||
pass->set_name(ustring(name));
|
||||
pass->set_mode(mode);
|
||||
|
||||
if (name.substr(0, 10) != "Denoising ") {
|
||||
return -1;
|
||||
}
|
||||
name = name.substr(10);
|
||||
|
||||
#define MAP_PASS(passname, offset) \
|
||||
if (name == passname) { \
|
||||
return offset; \
|
||||
} \
|
||||
((void)0)
|
||||
MAP_PASS("Normal", DENOISING_PASS_PREFILTERED_NORMAL);
|
||||
MAP_PASS("Albedo", DENOISING_PASS_PREFILTERED_ALBEDO);
|
||||
MAP_PASS("Depth", DENOISING_PASS_PREFILTERED_DEPTH);
|
||||
MAP_PASS("Shadowing", DENOISING_PASS_PREFILTERED_SHADOWING);
|
||||
MAP_PASS("Variance", DENOISING_PASS_PREFILTERED_VARIANCE);
|
||||
MAP_PASS("Intensity", DENOISING_PASS_PREFILTERED_INTENSITY);
|
||||
MAP_PASS("Clean", DENOISING_PASS_CLEAN);
|
||||
#undef MAP_PASS
|
||||
|
||||
return -1;
|
||||
return pass;
|
||||
}
|
||||
|
||||
vector<Pass> BlenderSync::sync_render_passes(BL::Scene &b_scene,
|
||||
BL::RenderLayer &b_rlay,
|
||||
BL::ViewLayer &b_view_layer,
|
||||
bool adaptive_sampling,
|
||||
const DenoiseParams &denoising)
|
||||
void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_view_layer)
|
||||
{
|
||||
vector<Pass> passes;
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
|
||||
/* loop over passes */
|
||||
/* Delete all existing passes. */
|
||||
set<Pass *> clear_passes(scene->passes.begin(), scene->passes.end());
|
||||
scene->delete_nodes(clear_passes);
|
||||
|
||||
/* Always add combined pass. */
|
||||
pass_add(scene, PASS_COMBINED, "Combined");
|
||||
|
||||
/* Blender built-in data and light passes. */
|
||||
for (BL::RenderPass &b_pass : b_rlay.passes) {
|
||||
PassType pass_type = get_pass_type(b_pass);
|
||||
const PassType pass_type = get_blender_pass_type(b_pass);
|
||||
|
||||
if (pass_type == PASS_NONE) {
|
||||
LOG(ERROR) << "Unknown pass " << b_pass.name();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pass_type == PASS_MOTION &&
|
||||
(b_view_layer.use_motion_blur() && b_scene.render().use_motion_blur())) {
|
||||
continue;
|
||||
}
|
||||
if (pass_type != PASS_NONE)
|
||||
Pass::add(pass_type, passes, b_pass.name().c_str());
|
||||
|
||||
pass_add(scene, pass_type, b_pass.name().c_str());
|
||||
}
|
||||
|
||||
PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
|
||||
|
||||
int denoising_flags = 0;
|
||||
if (denoising.use || denoising.store_passes) {
|
||||
if (denoising.type == DENOISER_NLM) {
|
||||
#define MAP_OPTION(name, flag) \
|
||||
if (!get_boolean(crl, name)) { \
|
||||
denoising_flags |= flag; \
|
||||
} \
|
||||
((void)0)
|
||||
MAP_OPTION("denoising_diffuse_direct", DENOISING_CLEAN_DIFFUSE_DIR);
|
||||
MAP_OPTION("denoising_diffuse_indirect", DENOISING_CLEAN_DIFFUSE_IND);
|
||||
MAP_OPTION("denoising_glossy_direct", DENOISING_CLEAN_GLOSSY_DIR);
|
||||
MAP_OPTION("denoising_glossy_indirect", DENOISING_CLEAN_GLOSSY_IND);
|
||||
MAP_OPTION("denoising_transmission_direct", DENOISING_CLEAN_TRANSMISSION_DIR);
|
||||
MAP_OPTION("denoising_transmission_indirect", DENOISING_CLEAN_TRANSMISSION_IND);
|
||||
#undef MAP_OPTION
|
||||
}
|
||||
b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str());
|
||||
}
|
||||
scene->film->set_denoising_flags(denoising_flags);
|
||||
|
||||
if (denoising.store_passes) {
|
||||
b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str());
|
||||
b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str());
|
||||
b_engine.add_pass("Denoising Depth", 1, "Z", b_view_layer.name().c_str());
|
||||
if (denoising.type == DENOISER_NLM) {
|
||||
b_engine.add_pass("Denoising Shadowing", 1, "X", b_view_layer.name().c_str());
|
||||
b_engine.add_pass("Denoising Variance", 3, "RGB", b_view_layer.name().c_str());
|
||||
b_engine.add_pass("Denoising Intensity", 1, "X", b_view_layer.name().c_str());
|
||||
}
|
||||
|
||||
if (scene->film->get_denoising_flags() & DENOISING_CLEAN_ALL_PASSES) {
|
||||
b_engine.add_pass("Denoising Clean", 3, "RGB", b_view_layer.name().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/* Debug passes. */
|
||||
if (get_boolean(crl, "pass_debug_render_time")) {
|
||||
b_engine.add_pass("Debug Render Time", 1, "X", b_view_layer.name().c_str());
|
||||
Pass::add(PASS_RENDER_TIME, passes, "Debug Render Time");
|
||||
pass_add(scene, PASS_RENDER_TIME, "Debug Render Time");
|
||||
}
|
||||
if (get_boolean(crl, "pass_debug_sample_count")) {
|
||||
b_engine.add_pass("Debug Sample Count", 1, "X", b_view_layer.name().c_str());
|
||||
Pass::add(PASS_SAMPLE_COUNT, passes, "Debug Sample Count");
|
||||
pass_add(scene, PASS_SAMPLE_COUNT, "Debug Sample Count");
|
||||
}
|
||||
|
||||
/* Cycles specific passes. */
|
||||
if (get_boolean(crl, "use_pass_volume_direct")) {
|
||||
b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str());
|
||||
Pass::add(PASS_VOLUME_DIRECT, passes, "VolumeDir");
|
||||
pass_add(scene, PASS_VOLUME_DIRECT, "VolumeDir");
|
||||
}
|
||||
if (get_boolean(crl, "use_pass_volume_indirect")) {
|
||||
b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str());
|
||||
Pass::add(PASS_VOLUME_INDIRECT, passes, "VolumeInd");
|
||||
pass_add(scene, PASS_VOLUME_INDIRECT, "VolumeInd");
|
||||
}
|
||||
if (get_boolean(crl, "use_pass_shadow_catcher")) {
|
||||
b_engine.add_pass("Shadow Catcher", 3, "RGB", b_view_layer.name().c_str());
|
||||
pass_add(scene, PASS_SHADOW_CATCHER, "Shadow Catcher");
|
||||
}
|
||||
|
||||
/* Cryptomatte stores two ID/weight pairs per RGBA layer.
|
||||
@@ -662,7 +636,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::Scene &b_scene,
|
||||
for (int i = 0; i < crypto_depth; i++) {
|
||||
string passname = cryptomatte_prefix + string_printf("Object%02d", i);
|
||||
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
|
||||
Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
|
||||
pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
|
||||
}
|
||||
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_OBJECT);
|
||||
}
|
||||
@@ -670,7 +644,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::Scene &b_scene,
|
||||
for (int i = 0; i < crypto_depth; i++) {
|
||||
string passname = cryptomatte_prefix + string_printf("Material%02d", i);
|
||||
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
|
||||
Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
|
||||
pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
|
||||
}
|
||||
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_MATERIAL);
|
||||
}
|
||||
@@ -678,22 +652,33 @@ vector<Pass> BlenderSync::sync_render_passes(BL::Scene &b_scene,
|
||||
for (int i = 0; i < crypto_depth; i++) {
|
||||
string passname = cryptomatte_prefix + string_printf("Asset%02d", i);
|
||||
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
|
||||
Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
|
||||
pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
|
||||
}
|
||||
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_ASSET);
|
||||
}
|
||||
if (b_view_layer.use_pass_cryptomatte_accurate() && cryptomatte_passes != CRYPT_NONE) {
|
||||
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_ACCURATE);
|
||||
}
|
||||
scene->film->set_cryptomatte_passes(cryptomatte_passes);
|
||||
|
||||
if (adaptive_sampling) {
|
||||
Pass::add(PASS_ADAPTIVE_AUX_BUFFER, passes);
|
||||
if (!get_boolean(crl, "pass_debug_sample_count")) {
|
||||
Pass::add(PASS_SAMPLE_COUNT, passes);
|
||||
/* Denoising passes. */
|
||||
const bool use_denoising = get_boolean(cscene, "use_denoising") &&
|
||||
get_boolean(crl, "use_denoising");
|
||||
const bool store_denoising_passes = get_boolean(crl, "denoising_store_passes");
|
||||
if (use_denoising) {
|
||||
b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str());
|
||||
pass_add(scene, PASS_COMBINED, "Noisy Image", PassMode::NOISY);
|
||||
if (get_boolean(crl, "use_pass_shadow_catcher")) {
|
||||
b_engine.add_pass("Noisy Shadow Catcher", 3, "RGB", b_view_layer.name().c_str());
|
||||
pass_add(scene, PASS_SHADOW_CATCHER, "Noisy Shadow Catcher", PassMode::NOISY);
|
||||
}
|
||||
}
|
||||
if (store_denoising_passes) {
|
||||
b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str());
|
||||
pass_add(scene, PASS_DENOISING_NORMAL, "Denoising Normal", PassMode::NOISY);
|
||||
|
||||
b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str());
|
||||
pass_add(scene, PASS_DENOISING_ALBEDO, "Denoising Albedo", PassMode::NOISY);
|
||||
}
|
||||
|
||||
/* Custom AOV passes. */
|
||||
BL::ViewLayer::aovs_iterator b_aov_iter;
|
||||
for (b_view_layer.aovs.begin(b_aov_iter); b_aov_iter != b_view_layer.aovs.end(); ++b_aov_iter) {
|
||||
BL::AOV b_aov(*b_aov_iter);
|
||||
@@ -706,28 +691,15 @@ vector<Pass> BlenderSync::sync_render_passes(BL::Scene &b_scene,
|
||||
|
||||
if (is_color) {
|
||||
b_engine.add_pass(name.c_str(), 4, "RGBA", b_view_layer.name().c_str());
|
||||
Pass::add(PASS_AOV_COLOR, passes, name.c_str());
|
||||
pass_add(scene, PASS_AOV_COLOR, name.c_str());
|
||||
}
|
||||
else {
|
||||
b_engine.add_pass(name.c_str(), 1, "X", b_view_layer.name().c_str());
|
||||
Pass::add(PASS_AOV_VALUE, passes, name.c_str());
|
||||
pass_add(scene, PASS_AOV_VALUE, name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
scene->film->set_denoising_data_pass(denoising.use || denoising.store_passes);
|
||||
scene->film->set_denoising_clean_pass(scene->film->get_denoising_flags() &
|
||||
DENOISING_CLEAN_ALL_PASSES);
|
||||
scene->film->set_denoising_prefiltered_pass(denoising.store_passes &&
|
||||
denoising.type == DENOISER_NLM);
|
||||
scene->film->set_pass_alpha_threshold(b_view_layer.pass_alpha_threshold());
|
||||
|
||||
if (!Pass::equals(passes, scene->passes)) {
|
||||
scene->film->tag_passes_update(scene, passes);
|
||||
scene->film->tag_modified();
|
||||
scene->integrator->tag_update(scene, Integrator::UPDATE_ALL);
|
||||
}
|
||||
|
||||
return passes;
|
||||
}
|
||||
|
||||
void BlenderSync::free_data_after_sync(BL::Depsgraph &b_depsgraph)
|
||||
@@ -773,9 +745,9 @@ SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background)
|
||||
params.shadingsystem = SHADINGSYSTEM_OSL;
|
||||
|
||||
if (background || DebugFlags().viewport_static_bvh)
|
||||
params.bvh_type = SceneParams::BVH_STATIC;
|
||||
params.bvh_type = BVH_TYPE_STATIC;
|
||||
else
|
||||
params.bvh_type = SceneParams::BVH_DYNAMIC;
|
||||
params.bvh_type = BVH_TYPE_DYNAMIC;
|
||||
|
||||
params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");
|
||||
params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh");
|
||||
@@ -818,8 +790,7 @@ bool BlenderSync::get_session_pause(BL::Scene &b_scene, bool background)
|
||||
SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
|
||||
BL::Preferences &b_preferences,
|
||||
BL::Scene &b_scene,
|
||||
bool background,
|
||||
BL::ViewLayer b_view_layer)
|
||||
bool background)
|
||||
{
|
||||
SessionParams params;
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
@@ -827,7 +798,8 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
|
||||
/* feature set */
|
||||
params.experimental = (get_enum(cscene, "feature_set") != 0);
|
||||
|
||||
/* Background */
|
||||
/* Headless and background rendering. */
|
||||
params.headless = BlenderSession::headless;
|
||||
params.background = background;
|
||||
|
||||
/* Device */
|
||||
@@ -836,111 +808,26 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
|
||||
|
||||
/* samples */
|
||||
int samples = get_int(cscene, "samples");
|
||||
int aa_samples = get_int(cscene, "aa_samples");
|
||||
int preview_samples = get_int(cscene, "preview_samples");
|
||||
int preview_aa_samples = get_int(cscene, "preview_aa_samples");
|
||||
|
||||
if (get_boolean(cscene, "use_square_samples")) {
|
||||
aa_samples = aa_samples * aa_samples;
|
||||
preview_aa_samples = preview_aa_samples * preview_aa_samples;
|
||||
|
||||
samples = samples * samples;
|
||||
preview_samples = preview_samples * preview_samples;
|
||||
}
|
||||
|
||||
if (get_enum(cscene, "progressive") == 0 && params.device.has_branched_path) {
|
||||
if (background) {
|
||||
params.samples = aa_samples;
|
||||
}
|
||||
else {
|
||||
params.samples = preview_aa_samples;
|
||||
if (params.samples == 0)
|
||||
params.samples = INT_MAX;
|
||||
}
|
||||
if (background) {
|
||||
params.samples = samples;
|
||||
}
|
||||
else {
|
||||
if (background) {
|
||||
params.samples = samples;
|
||||
}
|
||||
else {
|
||||
params.samples = preview_samples;
|
||||
if (params.samples == 0)
|
||||
params.samples = INT_MAX;
|
||||
}
|
||||
params.samples = preview_samples;
|
||||
if (params.samples == 0)
|
||||
params.samples = INT_MAX;
|
||||
}
|
||||
|
||||
/* Clamp samples. */
|
||||
params.samples = min(params.samples, Integrator::MAX_SAMPLES);
|
||||
|
||||
/* Adaptive sampling. */
|
||||
params.adaptive_sampling = RNA_boolean_get(&cscene, "use_adaptive_sampling");
|
||||
|
||||
/* tiles */
|
||||
const bool is_cpu = (params.device.type == DEVICE_CPU);
|
||||
if (!is_cpu && !background) {
|
||||
/* currently GPU could be much slower than CPU when using tiles,
|
||||
* still need to be investigated, but meanwhile make it possible
|
||||
* to work in viewport smoothly
|
||||
*/
|
||||
int debug_tile_size = get_int(cscene, "debug_tile_size");
|
||||
|
||||
params.tile_size = make_int2(debug_tile_size, debug_tile_size);
|
||||
}
|
||||
else {
|
||||
int tile_x = b_engine.tile_x();
|
||||
int tile_y = b_engine.tile_y();
|
||||
|
||||
params.tile_size = make_int2(tile_x, tile_y);
|
||||
}
|
||||
|
||||
if ((BlenderSession::headless == false) && background) {
|
||||
params.tile_order = (TileOrder)get_enum(cscene, "tile_order");
|
||||
}
|
||||
else {
|
||||
params.tile_order = TILE_BOTTOM_TO_TOP;
|
||||
}
|
||||
|
||||
/* Denoising */
|
||||
params.denoising = get_denoise_params(b_scene, b_view_layer, background);
|
||||
|
||||
if (params.denoising.use) {
|
||||
/* Add additional denoising devices if we are rendering and denoising
|
||||
* with different devices. */
|
||||
params.device.add_denoising_devices(params.denoising.type);
|
||||
|
||||
/* Check if denoiser is supported by device. */
|
||||
if (!(params.device.denoisers & params.denoising.type)) {
|
||||
params.denoising.use = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Viewport Performance */
|
||||
params.start_resolution = get_int(cscene, "preview_start_resolution");
|
||||
params.pixel_size = b_engine.get_preview_pixel_size(b_scene);
|
||||
|
||||
/* other parameters */
|
||||
params.cancel_timeout = (double)get_float(cscene, "debug_cancel_timeout");
|
||||
params.reset_timeout = (double)get_float(cscene, "debug_reset_timeout");
|
||||
params.text_timeout = (double)get_float(cscene, "debug_text_timeout");
|
||||
|
||||
/* progressive refine */
|
||||
BL::RenderSettings b_r = b_scene.render();
|
||||
params.progressive_refine = b_engine.is_preview() ||
|
||||
get_boolean(cscene, "use_progressive_refine");
|
||||
if (b_r.use_save_buffers() || params.adaptive_sampling)
|
||||
params.progressive_refine = false;
|
||||
|
||||
if (background) {
|
||||
if (params.progressive_refine)
|
||||
params.progressive = true;
|
||||
else
|
||||
params.progressive = false;
|
||||
|
||||
params.start_resolution = INT_MAX;
|
||||
params.pixel_size = 1;
|
||||
}
|
||||
else
|
||||
params.progressive = true;
|
||||
|
||||
/* shading system - scene level needs full refresh */
|
||||
const bool shadingsystem = RNA_boolean_get(&cscene, "shading_system");
|
||||
@@ -950,19 +837,30 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
|
||||
else if (shadingsystem == 1)
|
||||
params.shadingsystem = SHADINGSYSTEM_OSL;
|
||||
|
||||
/* Color management. */
|
||||
params.display_buffer_linear = b_engine.support_display_space_shader(b_scene);
|
||||
|
||||
if (b_engine.is_preview()) {
|
||||
/* For preview rendering we're using same timeout as
|
||||
* blender's job update.
|
||||
*/
|
||||
params.progressive_update_timeout = 0.1;
|
||||
/* Time limit. */
|
||||
if (background) {
|
||||
params.time_limit = get_float(cscene, "time_limit");
|
||||
}
|
||||
else {
|
||||
/* For the viewport it kind of makes more sense to think in terms of the noise floor, which is
|
||||
* usually higher than acceptable level for the final frame. */
|
||||
/* TODO: It might be useful to support time limit in the viewport as well, but needs some
|
||||
* extra thoughts and input. */
|
||||
params.time_limit = 0.0;
|
||||
}
|
||||
|
||||
/* Profiling. */
|
||||
params.use_profiling = params.device.has_profiling && !b_engine.is_preview() && background &&
|
||||
BlenderSession::print_render_stats;
|
||||
|
||||
if (background) {
|
||||
params.use_auto_tile = RNA_boolean_get(&cscene, "use_auto_tile");
|
||||
params.tile_size = get_int(cscene, "tile_size");
|
||||
}
|
||||
else {
|
||||
params.use_auto_tile = false;
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
@@ -970,33 +868,34 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
|
||||
BL::ViewLayer &b_view_layer,
|
||||
bool background)
|
||||
{
|
||||
enum DenoiserInput {
|
||||
DENOISER_INPUT_RGB = 1,
|
||||
DENOISER_INPUT_RGB_ALBEDO = 2,
|
||||
DENOISER_INPUT_RGB_ALBEDO_NORMAL = 3,
|
||||
|
||||
DENOISER_INPUT_NUM,
|
||||
};
|
||||
|
||||
DenoiseParams denoising;
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
|
||||
int input_passes = -1;
|
||||
|
||||
if (background) {
|
||||
/* Final Render Denoising */
|
||||
denoising.use = get_boolean(cscene, "use_denoising");
|
||||
denoising.type = (DenoiserType)get_enum(cscene, "denoiser", DENOISER_NUM, DENOISER_NONE);
|
||||
denoising.prefilter = (DenoiserPrefilter)get_enum(
|
||||
cscene, "denoising_prefilter", DENOISER_PREFILTER_NUM, DENOISER_PREFILTER_NONE);
|
||||
|
||||
input_passes = (DenoiserInput)get_enum(
|
||||
cscene, "denoising_input_passes", DENOISER_INPUT_NUM, DENOISER_INPUT_RGB_ALBEDO_NORMAL);
|
||||
|
||||
if (b_view_layer) {
|
||||
PointerRNA clayer = RNA_pointer_get(&b_view_layer.ptr, "cycles");
|
||||
if (!get_boolean(clayer, "use_denoising")) {
|
||||
denoising.use = false;
|
||||
}
|
||||
|
||||
denoising.radius = get_int(clayer, "denoising_radius");
|
||||
denoising.strength = get_float(clayer, "denoising_strength");
|
||||
denoising.feature_strength = get_float(clayer, "denoising_feature_strength");
|
||||
denoising.relative_pca = get_boolean(clayer, "denoising_relative_pca");
|
||||
|
||||
denoising.input_passes = (DenoiserInput)get_enum(
|
||||
clayer,
|
||||
(denoising.type == DENOISER_OPTIX) ? "denoising_optix_input_passes" :
|
||||
"denoising_openimagedenoise_input_passes",
|
||||
DENOISER_INPUT_NUM,
|
||||
DENOISER_INPUT_RGB_ALBEDO_NORMAL);
|
||||
|
||||
denoising.store_passes = get_boolean(clayer, "denoising_store_passes");
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1004,10 +903,12 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
|
||||
denoising.use = get_boolean(cscene, "use_preview_denoising");
|
||||
denoising.type = (DenoiserType)get_enum(
|
||||
cscene, "preview_denoiser", DENOISER_NUM, DENOISER_NONE);
|
||||
denoising.prefilter = (DenoiserPrefilter)get_enum(
|
||||
cscene, "preview_denoising_prefilter", DENOISER_PREFILTER_NUM, DENOISER_PREFILTER_FAST);
|
||||
denoising.start_sample = get_int(cscene, "preview_denoising_start_sample");
|
||||
|
||||
denoising.input_passes = (DenoiserInput)get_enum(
|
||||
cscene, "preview_denoising_input_passes", DENOISER_INPUT_NUM, (int)denoising.input_passes);
|
||||
input_passes = (DenoiserInput)get_enum(
|
||||
cscene, "preview_denoising_input_passes", DENOISER_INPUT_NUM, DENOISER_INPUT_RGB_ALBEDO);
|
||||
|
||||
/* Auto select fastest denoiser. */
|
||||
if (denoising.type == DENOISER_NONE) {
|
||||
@@ -1023,6 +924,27 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
|
||||
}
|
||||
}
|
||||
|
||||
switch (input_passes) {
|
||||
case DENOISER_INPUT_RGB:
|
||||
denoising.use_pass_albedo = false;
|
||||
denoising.use_pass_normal = false;
|
||||
break;
|
||||
|
||||
case DENOISER_INPUT_RGB_ALBEDO:
|
||||
denoising.use_pass_albedo = true;
|
||||
denoising.use_pass_normal = false;
|
||||
break;
|
||||
|
||||
case DENOISER_INPUT_RGB_ALBEDO_NORMAL:
|
||||
denoising.use_pass_albedo = true;
|
||||
denoising.use_pass_normal = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG(ERROR) << "Unhandled input passes enum " << input_passes;
|
||||
break;
|
||||
}
|
||||
|
||||
return denoising;
|
||||
}
|
||||
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include "RNA_types.h"
|
||||
|
||||
#include "blender/blender_id_map.h"
|
||||
#include "blender/blender_util.h"
|
||||
#include "blender/blender_viewport.h"
|
||||
|
||||
#include "render/scene.h"
|
||||
@@ -59,6 +60,7 @@ class BlenderSync {
|
||||
BL::Scene &b_scene,
|
||||
Scene *scene,
|
||||
bool preview,
|
||||
bool use_developer_ui,
|
||||
Progress &progress);
|
||||
~BlenderSync();
|
||||
|
||||
@@ -74,12 +76,8 @@ class BlenderSync {
|
||||
int height,
|
||||
void **python_thread_state);
|
||||
void sync_view_layer(BL::ViewLayer &b_view_layer);
|
||||
vector<Pass> sync_render_passes(BL::Scene &b_scene,
|
||||
BL::RenderLayer &b_render_layer,
|
||||
BL::ViewLayer &b_view_layer,
|
||||
bool adaptive_sampling,
|
||||
const DenoiseParams &denoising);
|
||||
void sync_integrator();
|
||||
void sync_render_passes(BL::RenderLayer &b_render_layer, BL::ViewLayer &b_view_layer);
|
||||
void sync_integrator(BL::ViewLayer &b_view_layer, bool background);
|
||||
void sync_camera(BL::RenderSettings &b_render,
|
||||
BL::Object &b_override,
|
||||
int width,
|
||||
@@ -97,22 +95,13 @@ class BlenderSync {
|
||||
|
||||
/* get parameters */
|
||||
static SceneParams get_scene_params(BL::Scene &b_scene, bool background);
|
||||
static SessionParams get_session_params(
|
||||
BL::RenderEngine &b_engine,
|
||||
BL::Preferences &b_userpref,
|
||||
BL::Scene &b_scene,
|
||||
bool background,
|
||||
BL::ViewLayer b_view_layer = BL::ViewLayer(PointerRNA_NULL));
|
||||
static SessionParams get_session_params(BL::RenderEngine &b_engine,
|
||||
BL::Preferences &b_userpref,
|
||||
BL::Scene &b_scene,
|
||||
bool background);
|
||||
static bool get_session_pause(BL::Scene &b_scene, bool background);
|
||||
static BufferParams get_buffer_params(BL::SpaceView3D &b_v3d,
|
||||
BL::RegionView3D &b_rv3d,
|
||||
Camera *cam,
|
||||
int width,
|
||||
int height,
|
||||
const bool use_denoiser);
|
||||
|
||||
static PassType get_pass_type(BL::RenderPass &b_pass);
|
||||
static int get_denoising_pass(BL::RenderPass &b_pass);
|
||||
static BufferParams get_buffer_params(
|
||||
BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, int height);
|
||||
|
||||
private:
|
||||
static DenoiseParams get_denoise_params(BL::Scene &b_scene,
|
||||
@@ -130,7 +119,7 @@ class BlenderSync {
|
||||
int width,
|
||||
int height,
|
||||
void **python_thread_state);
|
||||
void sync_film(BL::SpaceView3D &b_v3d);
|
||||
void sync_film(BL::ViewLayer &b_view_layer, BL::SpaceView3D &b_v3d);
|
||||
void sync_view();
|
||||
|
||||
/* Shader */
|
||||
@@ -158,18 +147,24 @@ class BlenderSync {
|
||||
bool sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object);
|
||||
|
||||
/* Volume */
|
||||
void sync_volume(BL::Object &b_ob, Volume *volume);
|
||||
void sync_volume(BObjectInfo &b_ob_info, Volume *volume);
|
||||
|
||||
/* Mesh */
|
||||
void sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh);
|
||||
void sync_mesh_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh, int motion_step);
|
||||
void sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh);
|
||||
void sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
||||
BObjectInfo &b_ob_info,
|
||||
Mesh *mesh,
|
||||
int motion_step);
|
||||
|
||||
/* Hair */
|
||||
void sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair);
|
||||
void sync_hair_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair, int motion_step);
|
||||
void sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step = 0);
|
||||
void sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Hair *hair);
|
||||
void sync_hair_motion(BL::Depsgraph b_depsgraph,
|
||||
BObjectInfo &b_ob_info,
|
||||
Hair *hair,
|
||||
int motion_step);
|
||||
void sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step = 0);
|
||||
void sync_particle_hair(
|
||||
Hair *hair, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0);
|
||||
Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step = 0);
|
||||
bool object_has_particle_hair(BL::Object b_ob);
|
||||
|
||||
/* Camera */
|
||||
@@ -178,14 +173,13 @@ class BlenderSync {
|
||||
|
||||
/* Geometry */
|
||||
Geometry *sync_geometry(BL::Depsgraph &b_depsgrpah,
|
||||
BL::Object &b_ob,
|
||||
BL::Object &b_ob_instance,
|
||||
BObjectInfo &b_ob_info,
|
||||
bool object_updated,
|
||||
bool use_particle_hair,
|
||||
TaskPool *task_pool);
|
||||
|
||||
void sync_geometry_motion(BL::Depsgraph &b_depsgraph,
|
||||
BL::Object &b_ob,
|
||||
BObjectInfo &b_ob_info,
|
||||
Object *object,
|
||||
float motion_time,
|
||||
bool use_particle_hair,
|
||||
@@ -194,8 +188,7 @@ class BlenderSync {
|
||||
/* Light */
|
||||
void sync_light(BL::Object &b_parent,
|
||||
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
|
||||
BL::Object &b_ob,
|
||||
BL::Object &b_ob_instance,
|
||||
BObjectInfo &b_ob_info,
|
||||
int random_id,
|
||||
Transform &tfm,
|
||||
bool *use_portal);
|
||||
@@ -231,6 +224,7 @@ class BlenderSync {
|
||||
id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
|
||||
set<Geometry *> geometry_synced;
|
||||
set<Geometry *> geometry_motion_synced;
|
||||
set<Geometry *> geometry_motion_attribute_synced;
|
||||
set<float> motion_times;
|
||||
void *world_map;
|
||||
bool world_recalc;
|
||||
@@ -239,6 +233,7 @@ class BlenderSync {
|
||||
Scene *scene;
|
||||
bool preview;
|
||||
bool experimental;
|
||||
bool use_developer_ui;
|
||||
|
||||
float dicing_rate;
|
||||
int max_subdivisions;
|
||||
@@ -247,7 +242,6 @@ class BlenderSync {
|
||||
RenderLayerInfo()
|
||||
: material_override(PointerRNA_NULL),
|
||||
use_background_shader(true),
|
||||
use_background_ao(true),
|
||||
use_surfaces(true),
|
||||
use_hair(true),
|
||||
use_volumes(true),
|
||||
@@ -260,7 +254,6 @@ class BlenderSync {
|
||||
string name;
|
||||
BL::Material material_override;
|
||||
bool use_background_shader;
|
||||
bool use_background_ao;
|
||||
bool use_surfaces;
|
||||
bool use_hair;
|
||||
bool use_volumes;
|
||||
|
@@ -40,6 +40,28 @@ float *BKE_image_get_float_pixels_for_frame(void *image, int frame, int tile);
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
struct BObjectInfo {
|
||||
/* Object directly provided by the depsgraph iterator. This object is only valid during one
|
||||
* iteration and must not be accessed afterwards. Transforms and visibility should be checked on
|
||||
* this object. */
|
||||
BL::Object iter_object;
|
||||
|
||||
/* This object remains alive even after the object iterator is done. It corresponds to one
|
||||
* original object. It is the object that owns the object data below. */
|
||||
BL::Object real_object;
|
||||
|
||||
/* The object-data referenced by the iter object. This is still valid after the depsgraph
|
||||
* iterator is done. It might have a different type compared to real_object.data(). */
|
||||
BL::ID object_data;
|
||||
|
||||
/* True when the current geometry is the data of the referenced object. False when it is a
|
||||
* geometry instance that does not have a 1-to-1 relationship with an object. */
|
||||
bool is_real_object_data() const
|
||||
{
|
||||
return const_cast<BL::Object &>(real_object).data() == object_data;
|
||||
}
|
||||
};
|
||||
|
||||
typedef BL::ShaderNodeAttribute::attribute_type_enum BlenderAttributeType;
|
||||
BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name);
|
||||
|
||||
@@ -47,7 +69,7 @@ void python_thread_state_save(void **python_thread_state);
|
||||
void python_thread_state_restore(void **python_thread_state);
|
||||
|
||||
static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
|
||||
BL::Object &object,
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Depsgraph & /*depsgraph*/,
|
||||
bool /*calc_undeformed*/,
|
||||
Mesh::SubdivisionType subdivision_type)
|
||||
@@ -69,9 +91,9 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
|
||||
#endif
|
||||
|
||||
BL::Mesh mesh(PointerRNA_NULL);
|
||||
if (object.type() == BL::Object::type_MESH) {
|
||||
if (b_ob_info.object_data.is_a(&RNA_Mesh)) {
|
||||
/* TODO: calc_undeformed is not used. */
|
||||
mesh = BL::Mesh(object.data());
|
||||
mesh = BL::Mesh(b_ob_info.object_data);
|
||||
|
||||
/* Make a copy to split faces if we use autosmooth, otherwise not needed.
|
||||
* Also in edit mode do we need to make a copy, to ensure data layers like
|
||||
@@ -79,12 +101,15 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
|
||||
if (mesh.is_editmode() ||
|
||||
(mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) {
|
||||
BL::Depsgraph depsgraph(PointerRNA_NULL);
|
||||
mesh = object.to_mesh(false, depsgraph);
|
||||
assert(b_ob_info.is_real_object_data());
|
||||
mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
|
||||
}
|
||||
}
|
||||
else {
|
||||
BL::Depsgraph depsgraph(PointerRNA_NULL);
|
||||
mesh = object.to_mesh(false, depsgraph);
|
||||
if (b_ob_info.is_real_object_data()) {
|
||||
mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -108,10 +133,14 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
|
||||
}
|
||||
|
||||
static inline void free_object_to_mesh(BL::BlendData & /*data*/,
|
||||
BL::Object &object,
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Mesh &mesh)
|
||||
{
|
||||
if (!b_ob_info.is_real_object_data()) {
|
||||
return;
|
||||
}
|
||||
/* Free mesh if we didn't just use the existing one. */
|
||||
BL::Object object = b_ob_info.real_object;
|
||||
if (object.data().ptr.data != mesh.ptr.data) {
|
||||
object.to_mesh_clear();
|
||||
}
|
||||
@@ -219,9 +248,13 @@ static inline bool BKE_object_is_modified(BL::Object &self, BL::Scene &scene, bo
|
||||
return self.is_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false;
|
||||
}
|
||||
|
||||
static inline bool BKE_object_is_deform_modified(BL::Object &self, BL::Scene &scene, bool preview)
|
||||
static inline bool BKE_object_is_deform_modified(BObjectInfo &self, BL::Scene &scene, bool preview)
|
||||
{
|
||||
return self.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false;
|
||||
if (!self.is_real_object_data()) {
|
||||
return false;
|
||||
}
|
||||
return self.real_object.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true :
|
||||
false;
|
||||
}
|
||||
|
||||
static inline int render_resolution_x(BL::RenderSettings &b_render)
|
||||
@@ -540,22 +573,6 @@ static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_
|
||||
return use_deform_motion;
|
||||
}
|
||||
|
||||
static inline BL::FluidDomainSettings object_fluid_liquid_domain_find(BL::Object &b_ob)
|
||||
{
|
||||
for (BL::Modifier &b_mod : b_ob.modifiers) {
|
||||
if (b_mod.is_a(&RNA_FluidModifier)) {
|
||||
BL::FluidModifier b_mmd(b_mod);
|
||||
|
||||
if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN &&
|
||||
b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_LIQUID) {
|
||||
return b_mmd.domain_settings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BL::FluidDomainSettings(PointerRNA_NULL);
|
||||
}
|
||||
|
||||
static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
|
||||
{
|
||||
for (BL::Modifier &b_mod : b_ob.modifiers) {
|
||||
@@ -573,7 +590,6 @@ static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b
|
||||
}
|
||||
|
||||
static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob,
|
||||
bool check_velocity,
|
||||
bool *has_subdivision_modifier)
|
||||
{
|
||||
for (int i = b_ob.modifiers.length() - 1; i >= 0; --i) {
|
||||
@@ -581,13 +597,6 @@ static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b
|
||||
|
||||
if (b_mod.type() == BL::Modifier::type_MESH_SEQUENCE_CACHE) {
|
||||
BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(b_mod);
|
||||
|
||||
if (check_velocity) {
|
||||
if (!MeshSequenceCacheModifier_has_velocity_get(&mesh_cache.ptr)) {
|
||||
return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return mesh_cache;
|
||||
}
|
||||
|
||||
@@ -596,9 +605,7 @@ static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Only skip the subsurf modifier if we are not checking for the mesh sequence cache modifier
|
||||
* for motion blur. */
|
||||
if (b_mod.type() == BL::Modifier::type_SUBSURF && !check_velocity) {
|
||||
if (b_mod.type() == BL::Modifier::type_SUBSURF) {
|
||||
if (has_subdivision_modifier) {
|
||||
*has_subdivision_modifier = true;
|
||||
}
|
||||
|
@@ -17,6 +17,8 @@
|
||||
#include "blender_viewport.h"
|
||||
|
||||
#include "blender_util.h"
|
||||
#include "render/pass.h"
|
||||
#include "util/util_logging.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
@@ -26,11 +28,12 @@ BlenderViewportParameters::BlenderViewportParameters()
|
||||
studiolight_rotate_z(0.0f),
|
||||
studiolight_intensity(1.0f),
|
||||
studiolight_background_alpha(1.0f),
|
||||
display_pass(PASS_COMBINED)
|
||||
display_pass(PASS_COMBINED),
|
||||
show_active_pixels(false)
|
||||
{
|
||||
}
|
||||
|
||||
BlenderViewportParameters::BlenderViewportParameters(BL::SpaceView3D &b_v3d)
|
||||
BlenderViewportParameters::BlenderViewportParameters(BL::SpaceView3D &b_v3d, bool use_developer_ui)
|
||||
: BlenderViewportParameters()
|
||||
{
|
||||
if (!b_v3d) {
|
||||
@@ -55,7 +58,25 @@ BlenderViewportParameters::BlenderViewportParameters(BL::SpaceView3D &b_v3d)
|
||||
}
|
||||
|
||||
/* Film. */
|
||||
display_pass = (PassType)get_enum(cshading, "render_pass", -1, -1);
|
||||
|
||||
/* Lookup display pass based on the enum identifier.
|
||||
* This is because integer values of python enum are not aligned with the passes definition in
|
||||
* the kernel. */
|
||||
|
||||
display_pass = PASS_COMBINED;
|
||||
|
||||
const string display_pass_identifier = get_enum_identifier(cshading, "render_pass");
|
||||
if (!display_pass_identifier.empty()) {
|
||||
const ustring pass_type_identifier(string_to_lower(display_pass_identifier));
|
||||
const NodeEnum *pass_type_enum = Pass::get_type_enum();
|
||||
if (pass_type_enum->exists(pass_type_identifier)) {
|
||||
display_pass = static_cast<PassType>((*pass_type_enum)[pass_type_identifier]);
|
||||
}
|
||||
}
|
||||
|
||||
if (use_developer_ui) {
|
||||
show_active_pixels = get_boolean(cshading, "show_active_pixels");
|
||||
}
|
||||
}
|
||||
|
||||
bool BlenderViewportParameters::shader_modified(const BlenderViewportParameters &other) const
|
||||
@@ -69,7 +90,7 @@ bool BlenderViewportParameters::shader_modified(const BlenderViewportParameters
|
||||
|
||||
bool BlenderViewportParameters::film_modified(const BlenderViewportParameters &other) const
|
||||
{
|
||||
return display_pass != other.display_pass;
|
||||
return display_pass != other.display_pass || show_active_pixels != other.show_active_pixels;
|
||||
}
|
||||
|
||||
bool BlenderViewportParameters::modified(const BlenderViewportParameters &other) const
|
||||
@@ -82,18 +103,4 @@ bool BlenderViewportParameters::use_custom_shader() const
|
||||
return !(use_scene_world && use_scene_lights);
|
||||
}
|
||||
|
||||
PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes)
|
||||
{
|
||||
if (b_v3d) {
|
||||
const BlenderViewportParameters viewport_parameters(b_v3d);
|
||||
const PassType display_pass = viewport_parameters.display_pass;
|
||||
|
||||
passes.clear();
|
||||
Pass::add(display_pass, passes);
|
||||
|
||||
return display_pass;
|
||||
}
|
||||
return PASS_NONE;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -39,9 +39,10 @@ class BlenderViewportParameters {
|
||||
|
||||
/* Film. */
|
||||
PassType display_pass;
|
||||
bool show_active_pixels;
|
||||
|
||||
BlenderViewportParameters();
|
||||
explicit BlenderViewportParameters(BL::SpaceView3D &b_v3d);
|
||||
BlenderViewportParameters(BL::SpaceView3D &b_v3d, bool use_developer_ui);
|
||||
|
||||
/* Check whether any of shading related settings are different from the given parameters. */
|
||||
bool shader_modified(const BlenderViewportParameters &other) const;
|
||||
@@ -57,8 +58,6 @@ class BlenderViewportParameters {
|
||||
bool use_custom_shader() const;
|
||||
};
|
||||
|
||||
PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes);
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
@@ -181,9 +181,12 @@ class BlenderSmokeLoader : public ImageLoader {
|
||||
AttributeStandard attribute;
|
||||
};
|
||||
|
||||
static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Volume *volume, float frame)
|
||||
static void sync_smoke_volume(Scene *scene, BObjectInfo &b_ob_info, Volume *volume, float frame)
|
||||
{
|
||||
BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob);
|
||||
if (!b_ob_info.is_real_object_data()) {
|
||||
return;
|
||||
}
|
||||
BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob_info.real_object);
|
||||
if (!b_domain) {
|
||||
return;
|
||||
}
|
||||
@@ -206,7 +209,7 @@ static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Volume *volume, fl
|
||||
|
||||
Attribute *attr = volume->attributes.add(std);
|
||||
|
||||
ImageLoader *loader = new BlenderSmokeLoader(b_ob, std);
|
||||
ImageLoader *loader = new BlenderSmokeLoader(b_ob_info.real_object, std);
|
||||
ImageParams params;
|
||||
params.frame = frame;
|
||||
|
||||
@@ -244,11 +247,11 @@ class BlenderVolumeLoader : public VDBImageLoader {
|
||||
};
|
||||
|
||||
static void sync_volume_object(BL::BlendData &b_data,
|
||||
BL::Object &b_ob,
|
||||
BObjectInfo &b_ob_info,
|
||||
Scene *scene,
|
||||
Volume *volume)
|
||||
{
|
||||
BL::Volume b_volume(b_ob.data());
|
||||
BL::Volume b_volume(b_ob_info.object_data);
|
||||
b_volume.grids.load(b_data.ptr.data);
|
||||
|
||||
BL::VolumeRender b_render(b_volume.render());
|
||||
@@ -296,19 +299,19 @@ static void sync_volume_object(BL::BlendData &b_data,
|
||||
}
|
||||
}
|
||||
|
||||
void BlenderSync::sync_volume(BL::Object &b_ob, Volume *volume)
|
||||
void BlenderSync::sync_volume(BObjectInfo &b_ob_info, Volume *volume)
|
||||
{
|
||||
volume->clear(true);
|
||||
|
||||
if (view_layer.use_volumes) {
|
||||
if (b_ob.type() == BL::Object::type_VOLUME) {
|
||||
if (b_ob_info.object_data.is_a(&RNA_Volume)) {
|
||||
/* Volume object. Create only attributes, bounding mesh will then
|
||||
* be automatically generated later. */
|
||||
sync_volume_object(b_data, b_ob, scene, volume);
|
||||
sync_volume_object(b_data, b_ob_info, scene, volume);
|
||||
}
|
||||
else {
|
||||
/* Smoke domain. */
|
||||
sync_smoke_volume(scene, b_ob, volume, b_scene.frame_current());
|
||||
sync_smoke_volume(scene, b_ob_info, volume, b_scene.frame_current());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -832,18 +832,18 @@ BVHNode *BVHBuild::create_leaf_node(const BVHRange &range, const vector<BVHRefer
|
||||
typedef StackAllocator<256, float2> LeafTimeStackAllocator;
|
||||
typedef StackAllocator<256, BVHReference> LeafReferenceStackAllocator;
|
||||
|
||||
vector<int, LeafStackAllocator> p_type[PRIMITIVE_NUM_TOTAL];
|
||||
vector<int, LeafStackAllocator> p_index[PRIMITIVE_NUM_TOTAL];
|
||||
vector<int, LeafStackAllocator> p_object[PRIMITIVE_NUM_TOTAL];
|
||||
vector<float2, LeafTimeStackAllocator> p_time[PRIMITIVE_NUM_TOTAL];
|
||||
vector<BVHReference, LeafReferenceStackAllocator> p_ref[PRIMITIVE_NUM_TOTAL];
|
||||
vector<int, LeafStackAllocator> p_type[PRIMITIVE_NUM];
|
||||
vector<int, LeafStackAllocator> p_index[PRIMITIVE_NUM];
|
||||
vector<int, LeafStackAllocator> p_object[PRIMITIVE_NUM];
|
||||
vector<float2, LeafTimeStackAllocator> p_time[PRIMITIVE_NUM];
|
||||
vector<BVHReference, LeafReferenceStackAllocator> p_ref[PRIMITIVE_NUM];
|
||||
|
||||
/* TODO(sergey): In theory we should be able to store references. */
|
||||
vector<BVHReference, LeafReferenceStackAllocator> object_references;
|
||||
|
||||
uint visibility[PRIMITIVE_NUM_TOTAL] = {0};
|
||||
uint visibility[PRIMITIVE_NUM] = {0};
|
||||
/* NOTE: Keep initialization in sync with actual number of primitives. */
|
||||
BoundBox bounds[PRIMITIVE_NUM_TOTAL] = {
|
||||
BoundBox bounds[PRIMITIVE_NUM] = {
|
||||
BoundBox::empty, BoundBox::empty, BoundBox::empty, BoundBox::empty};
|
||||
int ob_num = 0;
|
||||
int num_new_prims = 0;
|
||||
@@ -877,7 +877,7 @@ BVHNode *BVHBuild::create_leaf_node(const BVHRange &range, const vector<BVHRefer
|
||||
* TODO(sergey): With some pointer trickery we can write directly to the
|
||||
* destination buffers for the non-spatial split BVH.
|
||||
*/
|
||||
BVHNode *leaves[PRIMITIVE_NUM_TOTAL + 1] = {NULL};
|
||||
BVHNode *leaves[PRIMITIVE_NUM + 1] = {NULL};
|
||||
int num_leaves = 0;
|
||||
size_t start_index = 0;
|
||||
vector<int, LeafStackAllocator> local_prim_type, local_prim_index, local_prim_object;
|
||||
@@ -888,7 +888,7 @@ BVHNode *BVHBuild::create_leaf_node(const BVHRange &range, const vector<BVHRefer
|
||||
if (need_prim_time) {
|
||||
local_prim_time.resize(num_new_prims);
|
||||
}
|
||||
for (int i = 0; i < PRIMITIVE_NUM_TOTAL; ++i) {
|
||||
for (int i = 0; i < PRIMITIVE_NUM; ++i) {
|
||||
int num = (int)p_type[i].size();
|
||||
if (num != 0) {
|
||||
assert(p_type[i].size() == p_index[i].size());
|
||||
|
@@ -37,10 +37,10 @@
|
||||
/* Kernel includes are necessary so that the filter function for Embree can access the packed BVH.
|
||||
*/
|
||||
# include "kernel/bvh/bvh_embree.h"
|
||||
# include "kernel/kernel_compat_cpu.h"
|
||||
# include "kernel/kernel_globals.h"
|
||||
# include "kernel/bvh/bvh_util.h"
|
||||
# include "kernel/device/cpu/compat.h"
|
||||
# include "kernel/device/cpu/globals.h"
|
||||
# include "kernel/kernel_random.h"
|
||||
# include "kernel/split/kernel_split_data_types.h"
|
||||
|
||||
# include "render/hair.h"
|
||||
# include "render/mesh.h"
|
||||
@@ -73,46 +73,69 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
|
||||
const RTCRay *ray = (RTCRay *)args->ray;
|
||||
RTCHit *hit = (RTCHit *)args->hit;
|
||||
CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
|
||||
KernelGlobals *kg = ctx->kg;
|
||||
const KernelGlobals *kg = ctx->kg;
|
||||
|
||||
switch (ctx->type) {
|
||||
case CCLIntersectContext::RAY_SHADOW_ALL: {
|
||||
/* Append the intersection to the end of the array. */
|
||||
if (ctx->num_hits < ctx->max_hits) {
|
||||
Intersection current_isect;
|
||||
kernel_embree_convert_hit(kg, ray, hit, ¤t_isect);
|
||||
for (size_t i = 0; i < ctx->max_hits; ++i) {
|
||||
Intersection current_isect;
|
||||
kernel_embree_convert_hit(kg, ray, hit, ¤t_isect);
|
||||
|
||||
/* If no transparent shadows, all light is blocked. */
|
||||
const int flags = intersection_get_shader_flags(kg, ¤t_isect);
|
||||
if (!(flags & (SD_HAS_TRANSPARENT_SHADOW)) || ctx->max_hits == 0) {
|
||||
ctx->opaque_hit = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Test if we need to record this transparent intersection. */
|
||||
if (ctx->num_hits < ctx->max_hits || ray->tfar < ctx->max_t) {
|
||||
/* Skip already recorded intersections. */
|
||||
int num_recorded_hits = min(ctx->num_hits, ctx->max_hits);
|
||||
|
||||
for (int i = 0; i < num_recorded_hits; ++i) {
|
||||
if (current_isect.object == ctx->isect_s[i].object &&
|
||||
current_isect.prim == ctx->isect_s[i].prim && current_isect.t == ctx->isect_s[i].t) {
|
||||
/* This intersection was already recorded, skip it. */
|
||||
*args->valid = 0;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Intersection *isect = &ctx->isect_s[ctx->num_hits];
|
||||
++ctx->num_hits;
|
||||
*isect = current_isect;
|
||||
int prim = kernel_tex_fetch(__prim_index, isect->prim);
|
||||
int shader = 0;
|
||||
if (kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE) {
|
||||
shader = kernel_tex_fetch(__tri_shader, prim);
|
||||
}
|
||||
else {
|
||||
float4 str = kernel_tex_fetch(__curves, prim);
|
||||
shader = __float_as_int(str.z);
|
||||
}
|
||||
int flag = kernel_tex_fetch(__shaders, shader & SHADER_MASK).flags;
|
||||
/* If no transparent shadows, all light is blocked. */
|
||||
if (flag & (SD_HAS_TRANSPARENT_SHADOW)) {
|
||||
/* This tells Embree to continue tracing. */
|
||||
*args->valid = 0;
|
||||
|
||||
/* If maximum number of hits was reached, replace the intersection with the
|
||||
* highest distance. We want to find the N closest intersections. */
|
||||
int isect_index = num_recorded_hits;
|
||||
if (num_recorded_hits + 1 >= ctx->max_hits) {
|
||||
float max_t = ctx->isect_s[0].t;
|
||||
int max_recorded_hit = 0;
|
||||
|
||||
for (int i = 1; i < num_recorded_hits; ++i) {
|
||||
if (ctx->isect_s[i].t > max_t) {
|
||||
max_recorded_hit = i;
|
||||
max_t = ctx->isect_s[i].t;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_recorded_hits >= ctx->max_hits) {
|
||||
isect_index = max_recorded_hit;
|
||||
}
|
||||
|
||||
/* Limit the ray distance and stop counting hits beyond this.
|
||||
* TODO: is there some way we can tell Embree to stop intersecting beyond
|
||||
* this distance when max number of hits is reached?. Or maybe it will
|
||||
* become irrelevant if we make max_hits a very high number on the CPU. */
|
||||
ctx->max_t = max(current_isect.t, max_t);
|
||||
}
|
||||
|
||||
ctx->isect_s[isect_index] = current_isect;
|
||||
}
|
||||
else {
|
||||
/* Increase the number of hits beyond ray.max_hits
|
||||
* so that the caller can detect this as opaque. */
|
||||
++ctx->num_hits;
|
||||
}
|
||||
|
||||
/* Always increase the number of hits, even beyond ray.max_hits so that
|
||||
* the caller can detect this as and consider it opaque, or trace another
|
||||
* ray. */
|
||||
++ctx->num_hits;
|
||||
|
||||
/* This tells Embree to continue tracing. */
|
||||
*args->valid = 0;
|
||||
break;
|
||||
}
|
||||
case CCLIntersectContext::RAY_LOCAL:
|
||||
@@ -329,7 +352,7 @@ void BVHEmbree::build(Progress &progress, Stats *stats, RTCDevice rtc_device_)
|
||||
scene = NULL;
|
||||
}
|
||||
|
||||
const bool dynamic = params.bvh_type == SceneParams::BVH_DYNAMIC;
|
||||
const bool dynamic = params.bvh_type == BVH_TYPE_DYNAMIC;
|
||||
|
||||
scene = rtcNewScene(rtc_device);
|
||||
const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |
|
||||
|
@@ -31,6 +31,27 @@ CCL_NAMESPACE_BEGIN
|
||||
*/
|
||||
typedef KernelBVHLayout BVHLayout;
|
||||
|
||||
/* Type of BVH, in terms whether it is supported dynamic updates of meshes
|
||||
* or whether modifying geometry requires full BVH rebuild.
|
||||
*/
|
||||
enum BVHType {
|
||||
/* BVH supports dynamic updates of geometry.
|
||||
*
|
||||
* Faster for updating BVH tree when doing modifications in viewport,
|
||||
* but slower for rendering.
|
||||
*/
|
||||
BVH_TYPE_DYNAMIC = 0,
|
||||
/* BVH tree is calculated for specific scene, updates in geometry
|
||||
* requires full tree rebuild.
|
||||
*
|
||||
* Slower to update BVH tree when modifying objects in viewport, also
|
||||
* slower to build final BVH tree but gives best possible render speed.
|
||||
*/
|
||||
BVH_TYPE_STATIC = 1,
|
||||
|
||||
BVH_NUM_TYPES,
|
||||
};
|
||||
|
||||
/* Names bitflag type to denote which BVH layouts are supported by
|
||||
* particular area.
|
||||
*
|
||||
|
@@ -287,9 +287,6 @@ if(CYCLES_STANDALONE_REPOSITORY)
|
||||
endif()
|
||||
|
||||
set(__boost_packages filesystem regex system thread date_time)
|
||||
if(WITH_CYCLES_NETWORK)
|
||||
list(APPEND __boost_packages serialization)
|
||||
endif()
|
||||
if(WITH_CYCLES_OSL)
|
||||
list(APPEND __boost_packages wave)
|
||||
endif()
|
||||
|
@@ -36,49 +36,70 @@ endif()
|
||||
|
||||
set(SRC
|
||||
device.cpp
|
||||
device_cpu.cpp
|
||||
device_cuda.cpp
|
||||
device_denoising.cpp
|
||||
device_dummy.cpp
|
||||
device_denoise.cpp
|
||||
device_graphics_interop.cpp
|
||||
device_kernel.cpp
|
||||
device_memory.cpp
|
||||
device_multi.cpp
|
||||
device_opencl.cpp
|
||||
device_optix.cpp
|
||||
device_split_kernel.cpp
|
||||
device_task.cpp
|
||||
device_queue.cpp
|
||||
)
|
||||
|
||||
set(SRC_CPU
|
||||
cpu/device.cpp
|
||||
cpu/device.h
|
||||
cpu/device_impl.cpp
|
||||
cpu/device_impl.h
|
||||
cpu/kernel.cpp
|
||||
cpu/kernel.h
|
||||
cpu/kernel_function.h
|
||||
cpu/kernel_thread_globals.cpp
|
||||
cpu/kernel_thread_globals.h
|
||||
)
|
||||
|
||||
set(SRC_CUDA
|
||||
cuda/device_cuda.h
|
||||
cuda/device_cuda_impl.cpp
|
||||
cuda/device.cpp
|
||||
cuda/device.h
|
||||
cuda/device_impl.cpp
|
||||
cuda/device_impl.h
|
||||
cuda/graphics_interop.cpp
|
||||
cuda/graphics_interop.h
|
||||
cuda/kernel.cpp
|
||||
cuda/kernel.h
|
||||
cuda/queue.cpp
|
||||
cuda/queue.h
|
||||
cuda/util.cpp
|
||||
cuda/util.h
|
||||
)
|
||||
|
||||
set(SRC_OPENCL
|
||||
opencl/device_opencl.h
|
||||
opencl/device_opencl_impl.cpp
|
||||
opencl/memory_manager.h
|
||||
opencl/memory_manager.cpp
|
||||
opencl/opencl_util.cpp
|
||||
set(SRC_DUMMY
|
||||
dummy/device.cpp
|
||||
dummy/device.h
|
||||
)
|
||||
|
||||
if(WITH_CYCLES_NETWORK)
|
||||
list(APPEND SRC
|
||||
device_network.cpp
|
||||
)
|
||||
endif()
|
||||
set(SRC_MULTI
|
||||
multi/device.cpp
|
||||
multi/device.h
|
||||
)
|
||||
|
||||
set(SRC_OPTIX
|
||||
optix/device.cpp
|
||||
optix/device.h
|
||||
optix/device_impl.cpp
|
||||
optix/device_impl.h
|
||||
optix/queue.cpp
|
||||
optix/queue.h
|
||||
optix/util.h
|
||||
)
|
||||
|
||||
set(SRC_HEADERS
|
||||
device.h
|
||||
device_denoising.h
|
||||
device_denoise.h
|
||||
device_graphics_interop.h
|
||||
device_memory.h
|
||||
device_intern.h
|
||||
device_network.h
|
||||
device_split_kernel.h
|
||||
device_task.h
|
||||
device_kernel.h
|
||||
device_queue.h
|
||||
)
|
||||
|
||||
set(LIB
|
||||
cycles_render
|
||||
cycles_kernel
|
||||
cycles_util
|
||||
${CYCLES_GL_LIBRARIES}
|
||||
@@ -95,15 +116,7 @@ else()
|
||||
endif()
|
||||
|
||||
add_definitions(${GL_DEFINITIONS})
|
||||
if(WITH_CYCLES_NETWORK)
|
||||
add_definitions(-DWITH_NETWORK)
|
||||
endif()
|
||||
if(WITH_CYCLES_DEVICE_OPENCL)
|
||||
list(APPEND LIB
|
||||
extern_clew
|
||||
)
|
||||
add_definitions(-DWITH_OPENCL)
|
||||
endif()
|
||||
|
||||
if(WITH_CYCLES_DEVICE_CUDA)
|
||||
add_definitions(-DWITH_CUDA)
|
||||
endif()
|
||||
@@ -115,18 +128,27 @@ if(WITH_CYCLES_DEVICE_MULTI)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENIMAGEDENOISE)
|
||||
add_definitions(-DWITH_OPENIMAGEDENOISE)
|
||||
add_definitions(-DOIDN_STATIC_LIB)
|
||||
list(APPEND INC_SYS
|
||||
${OPENIMAGEDENOISE_INCLUDE_DIRS}
|
||||
)
|
||||
list(APPEND LIB
|
||||
${OPENIMAGEDENOISE_LIBRARIES}
|
||||
${TBB_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
include_directories(${INC})
|
||||
include_directories(SYSTEM ${INC_SYS})
|
||||
|
||||
cycles_add_library(cycles_device "${LIB}" ${SRC} ${SRC_CUDA} ${SRC_OPENCL} ${SRC_HEADERS})
|
||||
cycles_add_library(cycles_device "${LIB}"
|
||||
${SRC}
|
||||
${SRC_CPU}
|
||||
${SRC_CUDA}
|
||||
${SRC_DUMMY}
|
||||
${SRC_MULTI}
|
||||
${SRC_OPTIX}
|
||||
${SRC_HEADERS}
|
||||
)
|
||||
|
||||
source_group("cpu" FILES ${SRC_CPU})
|
||||
source_group("cuda" FILES ${SRC_CUDA})
|
||||
source_group("dummy" FILES ${SRC_DUMMY})
|
||||
source_group("multi" FILES ${SRC_MULTI})
|
||||
source_group("optix" FILES ${SRC_OPTIX})
|
||||
source_group("common" FILES ${SRC} ${SRC_HEADERS})
|
||||
|
64
intern/cycles/device/cpu/device.cpp
Normal file
64
intern/cycles/device/cpu/device.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2011-2013 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "device/cpu/device.h"
|
||||
#include "device/cpu/device_impl.h"
|
||||
|
||||
/* Used for `info.denoisers`. */
|
||||
/* TODO(sergey): The denoisers are probably to be moved completely out of the device into their
|
||||
* own class. But until then keep API consistent with how it used to work before. */
|
||||
#include "util/util_openimagedenoise.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
Device *device_cpu_create(const DeviceInfo &info, Stats &stats, Profiler &profiler)
|
||||
{
|
||||
return new CPUDevice(info, stats, profiler);
|
||||
}
|
||||
|
||||
void device_cpu_info(vector<DeviceInfo> &devices)
|
||||
{
|
||||
DeviceInfo info;
|
||||
|
||||
info.type = DEVICE_CPU;
|
||||
info.description = system_cpu_brand_string();
|
||||
info.id = "CPU";
|
||||
info.num = 0;
|
||||
info.has_osl = true;
|
||||
info.has_half_images = true;
|
||||
info.has_nanovdb = true;
|
||||
info.has_profiling = true;
|
||||
if (openimagedenoise_supported()) {
|
||||
info.denoisers |= DENOISER_OPENIMAGEDENOISE;
|
||||
}
|
||||
|
||||
devices.insert(devices.begin(), info);
|
||||
}
|
||||
|
||||
string device_cpu_capabilities()
|
||||
{
|
||||
string capabilities = "";
|
||||
capabilities += system_cpu_support_sse2() ? "SSE2 " : "";
|
||||
capabilities += system_cpu_support_sse3() ? "SSE3 " : "";
|
||||
capabilities += system_cpu_support_sse41() ? "SSE41 " : "";
|
||||
capabilities += system_cpu_support_avx() ? "AVX " : "";
|
||||
capabilities += system_cpu_support_avx2() ? "AVX2" : "";
|
||||
if (capabilities[capabilities.size() - 1] == ' ')
|
||||
capabilities.resize(capabilities.size() - 1);
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 Blender Foundation
|
||||
* Copyright 2011-2021 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,13 +14,22 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "kernel/kernel_compat_opencl.h"
|
||||
#include "kernel/split/kernel_split_common.h"
|
||||
#include "kernel/split/kernel_buffer_update.h"
|
||||
#pragma once
|
||||
|
||||
#define KERNEL_NAME buffer_update
|
||||
#define LOCALS_TYPE unsigned int
|
||||
#include "kernel/kernels/opencl/kernel_split_function.h"
|
||||
#undef KERNEL_NAME
|
||||
#undef LOCALS_TYPE
|
||||
#include "util/util_string.h"
|
||||
#include "util/util_vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class Device;
|
||||
class DeviceInfo;
|
||||
class Profiler;
|
||||
class Stats;
|
||||
|
||||
Device *device_cpu_create(const DeviceInfo &info, Stats &stats, Profiler &profiler);
|
||||
|
||||
void device_cpu_info(vector<DeviceInfo> &devices);
|
||||
|
||||
string device_cpu_capabilities();
|
||||
|
||||
CCL_NAMESPACE_END
|
481
intern/cycles/device/cpu/device_impl.cpp
Normal file
481
intern/cycles/device/cpu/device_impl.cpp
Normal file
@@ -0,0 +1,481 @@
|
||||
/*
|
||||
* Copyright 2011-2021 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "device/cpu/device_impl.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* So ImathMath is included before our kernel_cpu_compat. */
|
||||
#ifdef WITH_OSL
|
||||
/* So no context pollution happens from indirectly included windows.h */
|
||||
# include "util/util_windows.h"
|
||||
# include <OSL/oslexec.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_EMBREE
|
||||
# include <embree3/rtcore.h>
|
||||
#endif
|
||||
|
||||
#include "device/cpu/kernel.h"
|
||||
#include "device/cpu/kernel_thread_globals.h"
|
||||
|
||||
#include "device/device.h"
|
||||
|
||||
// clang-format off
|
||||
#include "kernel/device/cpu/compat.h"
|
||||
#include "kernel/device/cpu/globals.h"
|
||||
#include "kernel/device/cpu/kernel.h"
|
||||
#include "kernel/kernel_types.h"
|
||||
|
||||
#include "kernel/osl/osl_shader.h"
|
||||
#include "kernel/osl/osl_globals.h"
|
||||
// clang-format on
|
||||
|
||||
#include "bvh/bvh_embree.h"
|
||||
|
||||
#include "render/buffers.h"
|
||||
|
||||
#include "util/util_debug.h"
|
||||
#include "util/util_foreach.h"
|
||||
#include "util/util_function.h"
|
||||
#include "util/util_logging.h"
|
||||
#include "util/util_map.h"
|
||||
#include "util/util_opengl.h"
|
||||
#include "util/util_openimagedenoise.h"
|
||||
#include "util/util_optimization.h"
|
||||
#include "util/util_progress.h"
|
||||
#include "util/util_system.h"
|
||||
#include "util/util_task.h"
|
||||
#include "util/util_thread.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
CPUDevice::CPUDevice(const DeviceInfo &info_, Stats &stats_, Profiler &profiler_)
|
||||
: Device(info_, stats_, profiler_), texture_info(this, "__texture_info", MEM_GLOBAL)
|
||||
{
|
||||
/* Pick any kernel, all of them are supposed to have same level of microarchitecture
|
||||
* optimization. */
|
||||
VLOG(1) << "Will be using " << kernels.integrator_init_from_camera.get_uarch_name()
|
||||
<< " kernels.";
|
||||
|
||||
if (info.cpu_threads == 0) {
|
||||
info.cpu_threads = TaskScheduler::num_threads();
|
||||
}
|
||||
|
||||
#ifdef WITH_OSL
|
||||
kernel_globals.osl = &osl_globals;
|
||||
#endif
|
||||
#ifdef WITH_EMBREE
|
||||
embree_device = rtcNewDevice("verbose=0");
|
||||
#endif
|
||||
need_texture_info = false;
|
||||
}
|
||||
|
||||
CPUDevice::~CPUDevice()
|
||||
{
|
||||
#ifdef WITH_EMBREE
|
||||
rtcReleaseDevice(embree_device);
|
||||
#endif
|
||||
|
||||
texture_info.free();
|
||||
}
|
||||
|
||||
bool CPUDevice::show_samples() const
|
||||
{
|
||||
return (info.cpu_threads == 1);
|
||||
}
|
||||
|
||||
BVHLayoutMask CPUDevice::get_bvh_layout_mask() const
|
||||
{
|
||||
BVHLayoutMask bvh_layout_mask = BVH_LAYOUT_BVH2;
|
||||
#ifdef WITH_EMBREE
|
||||
bvh_layout_mask |= BVH_LAYOUT_EMBREE;
|
||||
#endif /* WITH_EMBREE */
|
||||
return bvh_layout_mask;
|
||||
}
|
||||
|
||||
bool CPUDevice::load_texture_info()
|
||||
{
|
||||
if (!need_texture_info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
texture_info.copy_to_device();
|
||||
need_texture_info = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPUDevice::mem_alloc(device_memory &mem)
|
||||
{
|
||||
if (mem.type == MEM_TEXTURE) {
|
||||
assert(!"mem_alloc not supported for textures.");
|
||||
}
|
||||
else if (mem.type == MEM_GLOBAL) {
|
||||
assert(!"mem_alloc not supported for global memory.");
|
||||
}
|
||||
else {
|
||||
if (mem.name) {
|
||||
VLOG(1) << "Buffer allocate: " << mem.name << ", "
|
||||
<< string_human_readable_number(mem.memory_size()) << " bytes. ("
|
||||
<< string_human_readable_size(mem.memory_size()) << ")";
|
||||
}
|
||||
|
||||
if (mem.type == MEM_DEVICE_ONLY) {
|
||||
assert(!mem.host_pointer);
|
||||
size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES;
|
||||
void *data = util_aligned_malloc(mem.memory_size(), alignment);
|
||||
mem.device_pointer = (device_ptr)data;
|
||||
}
|
||||
else {
|
||||
mem.device_pointer = (device_ptr)mem.host_pointer;
|
||||
}
|
||||
|
||||
mem.device_size = mem.memory_size();
|
||||
stats.mem_alloc(mem.device_size);
|
||||
}
|
||||
}
|
||||
|
||||
void CPUDevice::mem_copy_to(device_memory &mem)
|
||||
{
|
||||
if (mem.type == MEM_GLOBAL) {
|
||||
global_free(mem);
|
||||
global_alloc(mem);
|
||||
}
|
||||
else if (mem.type == MEM_TEXTURE) {
|
||||
tex_free((device_texture &)mem);
|
||||
tex_alloc((device_texture &)mem);
|
||||
}
|
||||
else {
|
||||
if (!mem.device_pointer) {
|
||||
mem_alloc(mem);
|
||||
}
|
||||
|
||||
/* copy is no-op */
|
||||
}
|
||||
}
|
||||
|
||||
void CPUDevice::mem_copy_from(
|
||||
device_memory & /*mem*/, int /*y*/, int /*w*/, int /*h*/, int /*elem*/)
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
void CPUDevice::mem_zero(device_memory &mem)
|
||||
{
|
||||
if (!mem.device_pointer) {
|
||||
mem_alloc(mem);
|
||||
}
|
||||
|
||||
if (mem.device_pointer) {
|
||||
memset((void *)mem.device_pointer, 0, mem.memory_size());
|
||||
}
|
||||
}
|
||||
|
||||
void CPUDevice::mem_free(device_memory &mem)
|
||||
{
|
||||
if (mem.type == MEM_GLOBAL) {
|
||||
global_free(mem);
|
||||
}
|
||||
else if (mem.type == MEM_TEXTURE) {
|
||||
tex_free((device_texture &)mem);
|
||||
}
|
||||
else if (mem.device_pointer) {
|
||||
if (mem.type == MEM_DEVICE_ONLY) {
|
||||
util_aligned_free((void *)mem.device_pointer);
|
||||
}
|
||||
mem.device_pointer = 0;
|
||||
stats.mem_free(mem.device_size);
|
||||
mem.device_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
device_ptr CPUDevice::mem_alloc_sub_ptr(device_memory &mem, int offset, int /*size*/)
|
||||
{
|
||||
return (device_ptr)(((char *)mem.device_pointer) + mem.memory_elements_size(offset));
|
||||
}
|
||||
|
||||
void CPUDevice::const_copy_to(const char *name, void *host, size_t size)
|
||||
{
|
||||
#if WITH_EMBREE
|
||||
if (strcmp(name, "__data") == 0) {
|
||||
assert(size <= sizeof(KernelData));
|
||||
|
||||
// Update scene handle (since it is different for each device on multi devices)
|
||||
KernelData *const data = (KernelData *)host;
|
||||
data->bvh.scene = embree_scene;
|
||||
}
|
||||
#endif
|
||||
kernel_const_copy(&kernel_globals, name, host, size);
|
||||
}
|
||||
|
||||
void CPUDevice::global_alloc(device_memory &mem)
|
||||
{
|
||||
VLOG(1) << "Global memory allocate: " << mem.name << ", "
|
||||
<< string_human_readable_number(mem.memory_size()) << " bytes. ("
|
||||
<< string_human_readable_size(mem.memory_size()) << ")";
|
||||
|
||||
kernel_global_memory_copy(&kernel_globals, mem.name, mem.host_pointer, mem.data_size);
|
||||
|
||||
mem.device_pointer = (device_ptr)mem.host_pointer;
|
||||
mem.device_size = mem.memory_size();
|
||||
stats.mem_alloc(mem.device_size);
|
||||
}
|
||||
|
||||
void CPUDevice::global_free(device_memory &mem)
|
||||
{
|
||||
if (mem.device_pointer) {
|
||||
mem.device_pointer = 0;
|
||||
stats.mem_free(mem.device_size);
|
||||
mem.device_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CPUDevice::tex_alloc(device_texture &mem)
|
||||
{
|
||||
VLOG(1) << "Texture allocate: " << mem.name << ", "
|
||||
<< string_human_readable_number(mem.memory_size()) << " bytes. ("
|
||||
<< string_human_readable_size(mem.memory_size()) << ")";
|
||||
|
||||
mem.device_pointer = (device_ptr)mem.host_pointer;
|
||||
mem.device_size = mem.memory_size();
|
||||
stats.mem_alloc(mem.device_size);
|
||||
|
||||
const uint slot = mem.slot;
|
||||
if (slot >= texture_info.size()) {
|
||||
/* Allocate some slots in advance, to reduce amount of re-allocations. */
|
||||
texture_info.resize(slot + 128);
|
||||
}
|
||||
|
||||
texture_info[slot] = mem.info;
|
||||
texture_info[slot].data = (uint64_t)mem.host_pointer;
|
||||
need_texture_info = true;
|
||||
}
|
||||
|
||||
void CPUDevice::tex_free(device_texture &mem)
|
||||
{
|
||||
if (mem.device_pointer) {
|
||||
mem.device_pointer = 0;
|
||||
stats.mem_free(mem.device_size);
|
||||
mem.device_size = 0;
|
||||
need_texture_info = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CPUDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
|
||||
{
|
||||
#ifdef WITH_EMBREE
|
||||
if (bvh->params.bvh_layout == BVH_LAYOUT_EMBREE ||
|
||||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE) {
|
||||
BVHEmbree *const bvh_embree = static_cast<BVHEmbree *>(bvh);
|
||||
if (refit) {
|
||||
bvh_embree->refit(progress);
|
||||
}
|
||||
else {
|
||||
bvh_embree->build(progress, &stats, embree_device);
|
||||
}
|
||||
|
||||
if (bvh->params.top_level) {
|
||||
embree_scene = bvh_embree->scene;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
Device::build_bvh(bvh, progress, refit);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void CPUDevice::render(DeviceTask &task, RenderTile &tile, KernelGlobals *kg)
|
||||
{
|
||||
const bool use_coverage = kernel_data.film.cryptomatte_passes & CRYPT_ACCURATE;
|
||||
|
||||
scoped_timer timer(&tile.buffers->render_time);
|
||||
|
||||
Coverage coverage(kg, tile);
|
||||
if (use_coverage) {
|
||||
coverage.init_path_trace();
|
||||
}
|
||||
|
||||
float *render_buffer = (float *)tile.buffer;
|
||||
int start_sample = tile.start_sample;
|
||||
int end_sample = tile.start_sample + tile.num_samples;
|
||||
|
||||
/* Needed for Embree. */
|
||||
SIMD_SET_FLUSH_TO_ZERO;
|
||||
|
||||
for (int sample = start_sample; sample < end_sample; sample++) {
|
||||
if (task.get_cancel() || TaskPool::canceled()) {
|
||||
if (task.need_finish_queue == false)
|
||||
break;
|
||||
}
|
||||
|
||||
if (tile.stealing_state == RenderTile::CAN_BE_STOLEN && task.get_tile_stolen()) {
|
||||
tile.stealing_state = RenderTile::WAS_STOLEN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tile.task == RenderTile::PATH_TRACE) {
|
||||
for (int y = tile.y; y < tile.y + tile.h; y++) {
|
||||
for (int x = tile.x; x < tile.x + tile.w; x++) {
|
||||
if (use_coverage) {
|
||||
coverage.init_pixel(x, y);
|
||||
}
|
||||
kernels.path_trace(kg, render_buffer, sample, x, y, tile.offset, tile.stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int y = tile.y; y < tile.y + tile.h; y++) {
|
||||
for (int x = tile.x; x < tile.x + tile.w; x++) {
|
||||
kernels.bake(kg, render_buffer, sample, x, y, tile.offset, tile.stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
tile.sample = sample + 1;
|
||||
|
||||
if (task.adaptive_sampling.use && task.adaptive_sampling.need_filter(sample)) {
|
||||
const bool stop = adaptive_sampling_filter(kg, tile, sample);
|
||||
if (stop) {
|
||||
const int num_progress_samples = end_sample - sample;
|
||||
tile.sample = end_sample;
|
||||
task.update_progress(&tile, tile.w * tile.h * num_progress_samples);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
task.update_progress(&tile, tile.w * tile.h);
|
||||
}
|
||||
if (use_coverage) {
|
||||
coverage.finalize();
|
||||
}
|
||||
|
||||
if (task.adaptive_sampling.use && (tile.stealing_state != RenderTile::WAS_STOLEN)) {
|
||||
adaptive_sampling_post(tile, kg);
|
||||
}
|
||||
}
|
||||
|
||||
void CPUDevice::thread_render(DeviceTask &task)
|
||||
{
|
||||
if (TaskPool::canceled()) {
|
||||
if (task.need_finish_queue == false)
|
||||
return;
|
||||
}
|
||||
|
||||
/* allocate buffer for kernel globals */
|
||||
CPUKernelThreadGlobals kg(kernel_globals, get_cpu_osl_memory());
|
||||
|
||||
profiler.add_state(&kg.profiler);
|
||||
|
||||
/* NLM denoiser. */
|
||||
DenoisingTask *denoising = NULL;
|
||||
|
||||
/* OpenImageDenoise: we can only denoise with one thread at a time, so to
|
||||
* avoid waiting with mutex locks in the denoiser, we let only a single
|
||||
* thread acquire denoising tiles. */
|
||||
uint tile_types = task.tile_types;
|
||||
bool hold_denoise_lock = false;
|
||||
if ((tile_types & RenderTile::DENOISE) && task.denoising.type == DENOISER_OPENIMAGEDENOISE) {
|
||||
if (!oidn_task_lock.try_lock()) {
|
||||
tile_types &= ~RenderTile::DENOISE;
|
||||
hold_denoise_lock = true;
|
||||
}
|
||||
}
|
||||
|
||||
RenderTile tile;
|
||||
while (task.acquire_tile(this, tile, tile_types)) {
|
||||
if (tile.task == RenderTile::PATH_TRACE) {
|
||||
render(task, tile, &kg);
|
||||
}
|
||||
else if (tile.task == RenderTile::BAKE) {
|
||||
render(task, tile, &kg);
|
||||
}
|
||||
else if (tile.task == RenderTile::DENOISE) {
|
||||
denoise_openimagedenoise(task, tile);
|
||||
task.update_progress(&tile, tile.w * tile.h);
|
||||
}
|
||||
|
||||
task.release_tile(tile);
|
||||
|
||||
if (TaskPool::canceled()) {
|
||||
if (task.need_finish_queue == false)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hold_denoise_lock) {
|
||||
oidn_task_lock.unlock();
|
||||
}
|
||||
|
||||
profiler.remove_state(&kg.profiler);
|
||||
|
||||
delete denoising;
|
||||
}
|
||||
|
||||
void CPUDevice::thread_denoise(DeviceTask &task)
|
||||
{
|
||||
RenderTile tile;
|
||||
tile.x = task.x;
|
||||
tile.y = task.y;
|
||||
tile.w = task.w;
|
||||
tile.h = task.h;
|
||||
tile.buffer = task.buffer;
|
||||
tile.sample = task.sample + task.num_samples;
|
||||
tile.num_samples = task.num_samples;
|
||||
tile.start_sample = task.sample;
|
||||
tile.offset = task.offset;
|
||||
tile.stride = task.stride;
|
||||
tile.buffers = task.buffers;
|
||||
|
||||
denoise_openimagedenoise(task, tile);
|
||||
|
||||
task.update_progress(&tile, tile.w * tile.h);
|
||||
}
|
||||
#endif
|
||||
|
||||
const CPUKernels *CPUDevice::get_cpu_kernels() const
|
||||
{
|
||||
return &kernels;
|
||||
}
|
||||
|
||||
void CPUDevice::get_cpu_kernel_thread_globals(
|
||||
vector<CPUKernelThreadGlobals> &kernel_thread_globals)
|
||||
{
|
||||
/* Ensure latest texture info is loaded into kernel globals before returning. */
|
||||
load_texture_info();
|
||||
|
||||
kernel_thread_globals.clear();
|
||||
void *osl_memory = get_cpu_osl_memory();
|
||||
for (int i = 0; i < info.cpu_threads; i++) {
|
||||
kernel_thread_globals.emplace_back(kernel_globals, osl_memory, profiler);
|
||||
}
|
||||
}
|
||||
|
||||
void *CPUDevice::get_cpu_osl_memory()
|
||||
{
|
||||
#ifdef WITH_OSL
|
||||
return &osl_globals;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CPUDevice::load_kernels(const uint /*kernel_features*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
99
intern/cycles/device/cpu/device_impl.h
Normal file
99
intern/cycles/device/cpu/device_impl.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2011-2021 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* So ImathMath is included before our kernel_cpu_compat. */
|
||||
#ifdef WITH_OSL
|
||||
/* So no context pollution happens from indirectly included windows.h */
|
||||
# include "util/util_windows.h"
|
||||
# include <OSL/oslexec.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_EMBREE
|
||||
# include <embree3/rtcore.h>
|
||||
#endif
|
||||
|
||||
#include "device/cpu/kernel.h"
|
||||
#include "device/device.h"
|
||||
#include "device/device_memory.h"
|
||||
|
||||
// clang-format off
|
||||
#include "kernel/device/cpu/compat.h"
|
||||
#include "kernel/device/cpu/kernel.h"
|
||||
#include "kernel/device/cpu/globals.h"
|
||||
|
||||
#include "kernel/osl/osl_shader.h"
|
||||
#include "kernel/osl/osl_globals.h"
|
||||
// clang-format on
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class CPUDevice : public Device {
|
||||
public:
|
||||
KernelGlobals kernel_globals;
|
||||
|
||||
device_vector<TextureInfo> texture_info;
|
||||
bool need_texture_info;
|
||||
|
||||
#ifdef WITH_OSL
|
||||
OSLGlobals osl_globals;
|
||||
#endif
|
||||
#ifdef WITH_EMBREE
|
||||
RTCScene embree_scene = NULL;
|
||||
RTCDevice embree_device;
|
||||
#endif
|
||||
|
||||
CPUKernels kernels;
|
||||
|
||||
CPUDevice(const DeviceInfo &info_, Stats &stats_, Profiler &profiler_);
|
||||
~CPUDevice();
|
||||
|
||||
virtual bool show_samples() const override;
|
||||
|
||||
virtual BVHLayoutMask get_bvh_layout_mask() const override;
|
||||
|
||||
/* Returns true if the texture info was copied to the device (meaning, some more
|
||||
* re-initialization might be needed). */
|
||||
bool load_texture_info();
|
||||
|
||||
virtual void mem_alloc(device_memory &mem) override;
|
||||
virtual void mem_copy_to(device_memory &mem) override;
|
||||
virtual void mem_copy_from(device_memory &mem, int y, int w, int h, int elem) override;
|
||||
virtual void mem_zero(device_memory &mem) override;
|
||||
virtual void mem_free(device_memory &mem) override;
|
||||
virtual device_ptr mem_alloc_sub_ptr(device_memory &mem, int offset, int /*size*/) override;
|
||||
|
||||
virtual void const_copy_to(const char *name, void *host, size_t size) override;
|
||||
|
||||
void global_alloc(device_memory &mem);
|
||||
void global_free(device_memory &mem);
|
||||
|
||||
void tex_alloc(device_texture &mem);
|
||||
void tex_free(device_texture &mem);
|
||||
|
||||
void build_bvh(BVH *bvh, Progress &progress, bool refit) override;
|
||||
|
||||
virtual const CPUKernels *get_cpu_kernels() const override;
|
||||
virtual void get_cpu_kernel_thread_globals(
|
||||
vector<CPUKernelThreadGlobals> &kernel_thread_globals) override;
|
||||
virtual void *get_cpu_osl_memory() override;
|
||||
|
||||
protected:
|
||||
virtual bool load_kernels(uint /*kernel_features*/) override;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
61
intern/cycles/device/cpu/kernel.cpp
Normal file
61
intern/cycles/device/cpu/kernel.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2011-2021 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "device/cpu/kernel.h"
|
||||
|
||||
#include "kernel/device/cpu/kernel.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#define KERNEL_FUNCTIONS(name) \
|
||||
KERNEL_NAME_EVAL(cpu, name), KERNEL_NAME_EVAL(cpu_sse2, name), \
|
||||
KERNEL_NAME_EVAL(cpu_sse3, name), KERNEL_NAME_EVAL(cpu_sse41, name), \
|
||||
KERNEL_NAME_EVAL(cpu_avx, name), KERNEL_NAME_EVAL(cpu_avx2, name)
|
||||
|
||||
#define REGISTER_KERNEL(name) name(KERNEL_FUNCTIONS(name))
|
||||
|
||||
CPUKernels::CPUKernels()
|
||||
: /* Integrator. */
|
||||
REGISTER_KERNEL(integrator_init_from_camera),
|
||||
REGISTER_KERNEL(integrator_init_from_bake),
|
||||
REGISTER_KERNEL(integrator_intersect_closest),
|
||||
REGISTER_KERNEL(integrator_intersect_shadow),
|
||||
REGISTER_KERNEL(integrator_intersect_subsurface),
|
||||
REGISTER_KERNEL(integrator_intersect_volume_stack),
|
||||
REGISTER_KERNEL(integrator_shade_background),
|
||||
REGISTER_KERNEL(integrator_shade_light),
|
||||
REGISTER_KERNEL(integrator_shade_shadow),
|
||||
REGISTER_KERNEL(integrator_shade_surface),
|
||||
REGISTER_KERNEL(integrator_shade_volume),
|
||||
REGISTER_KERNEL(integrator_megakernel),
|
||||
/* Shader evaluation. */
|
||||
REGISTER_KERNEL(shader_eval_displace),
|
||||
REGISTER_KERNEL(shader_eval_background),
|
||||
/* Adaptive sampling. */
|
||||
REGISTER_KERNEL(adaptive_sampling_convergence_check),
|
||||
REGISTER_KERNEL(adaptive_sampling_filter_x),
|
||||
REGISTER_KERNEL(adaptive_sampling_filter_y),
|
||||
/* Cryptomatte. */
|
||||
REGISTER_KERNEL(cryptomatte_postprocess),
|
||||
/* Bake. */
|
||||
REGISTER_KERNEL(bake)
|
||||
{
|
||||
}
|
||||
|
||||
#undef REGISTER_KERNEL
|
||||
#undef KERNEL_FUNCTIONS
|
||||
|
||||
CCL_NAMESPACE_END
|
111
intern/cycles/device/cpu/kernel.h
Normal file
111
intern/cycles/device/cpu/kernel.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2011-2021 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "device/cpu/kernel_function.h"
|
||||
#include "util/util_types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
struct KernelGlobals;
|
||||
struct IntegratorStateCPU;
|
||||
struct TileInfo;
|
||||
|
||||
class CPUKernels {
|
||||
public:
|
||||
/* Integrator. */
|
||||
|
||||
using IntegratorFunction =
|
||||
CPUKernelFunction<void (*)(const KernelGlobals *kg, IntegratorStateCPU *state)>;
|
||||
using IntegratorShadeFunction = CPUKernelFunction<void (*)(
|
||||
const KernelGlobals *kg, IntegratorStateCPU *state, ccl_global float *render_buffer)>;
|
||||
using IntegratorInitFunction = CPUKernelFunction<bool (*)(const KernelGlobals *kg,
|
||||
IntegratorStateCPU *state,
|
||||
KernelWorkTile *tile,
|
||||
ccl_global float *render_buffer)>;
|
||||
|
||||
IntegratorInitFunction integrator_init_from_camera;
|
||||
IntegratorInitFunction integrator_init_from_bake;
|
||||
IntegratorFunction integrator_intersect_closest;
|
||||
IntegratorFunction integrator_intersect_shadow;
|
||||
IntegratorFunction integrator_intersect_subsurface;
|
||||
IntegratorFunction integrator_intersect_volume_stack;
|
||||
IntegratorShadeFunction integrator_shade_background;
|
||||
IntegratorShadeFunction integrator_shade_light;
|
||||
IntegratorShadeFunction integrator_shade_shadow;
|
||||
IntegratorShadeFunction integrator_shade_surface;
|
||||
IntegratorShadeFunction integrator_shade_volume;
|
||||
IntegratorShadeFunction integrator_megakernel;
|
||||
|
||||
/* Shader evaluation. */
|
||||
|
||||
using ShaderEvalFunction = CPUKernelFunction<void (*)(
|
||||
const KernelGlobals *kg, const KernelShaderEvalInput *, float4 *, const int)>;
|
||||
|
||||
ShaderEvalFunction shader_eval_displace;
|
||||
ShaderEvalFunction shader_eval_background;
|
||||
|
||||
/* Adaptive stopping. */
|
||||
|
||||
using AdaptiveSamplingConvergenceCheckFunction =
|
||||
CPUKernelFunction<bool (*)(const KernelGlobals *kg,
|
||||
ccl_global float *render_buffer,
|
||||
int x,
|
||||
int y,
|
||||
float threshold,
|
||||
bool reset,
|
||||
int offset,
|
||||
int stride)>;
|
||||
|
||||
using AdaptiveSamplingFilterXFunction =
|
||||
CPUKernelFunction<void (*)(const KernelGlobals *kg,
|
||||
ccl_global float *render_buffer,
|
||||
int y,
|
||||
int start_x,
|
||||
int width,
|
||||
int offset,
|
||||
int stride)>;
|
||||
|
||||
using AdaptiveSamplingFilterYFunction =
|
||||
CPUKernelFunction<void (*)(const KernelGlobals *kg,
|
||||
ccl_global float *render_buffer,
|
||||
int x,
|
||||
int start_y,
|
||||
int height,
|
||||
int offset,
|
||||
int stride)>;
|
||||
|
||||
AdaptiveSamplingConvergenceCheckFunction adaptive_sampling_convergence_check;
|
||||
|
||||
AdaptiveSamplingFilterXFunction adaptive_sampling_filter_x;
|
||||
AdaptiveSamplingFilterYFunction adaptive_sampling_filter_y;
|
||||
|
||||
/* Cryptomatte. */
|
||||
|
||||
using CryptomattePostprocessFunction = CPUKernelFunction<void (*)(
|
||||
const KernelGlobals *kg, ccl_global float *render_buffer, int pixel_index)>;
|
||||
|
||||
CryptomattePostprocessFunction cryptomatte_postprocess;
|
||||
|
||||
/* Bake. */
|
||||
|
||||
CPUKernelFunction<void (*)(const KernelGlobals *, float *, int, int, int, int, int)> bake;
|
||||
|
||||
CPUKernels();
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
124
intern/cycles/device/cpu/kernel_function.h
Normal file
124
intern/cycles/device/cpu/kernel_function.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2011-2021 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/util_debug.h"
|
||||
#include "util/util_system.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* A wrapper around per-microarchitecture variant of a kernel function.
|
||||
*
|
||||
* Provides a function-call-like API which gets routed to the most suitable implementation.
|
||||
*
|
||||
* For example, on a computer which only has SSE4.1 the kernel_sse41 will be used. */
|
||||
template<typename FunctionType> class CPUKernelFunction {
|
||||
public:
|
||||
CPUKernelFunction(FunctionType kernel_default,
|
||||
FunctionType kernel_sse2,
|
||||
FunctionType kernel_sse3,
|
||||
FunctionType kernel_sse41,
|
||||
FunctionType kernel_avx,
|
||||
FunctionType kernel_avx2)
|
||||
{
|
||||
kernel_info_ = get_best_kernel_info(
|
||||
kernel_default, kernel_sse2, kernel_sse3, kernel_sse41, kernel_avx, kernel_avx2);
|
||||
}
|
||||
|
||||
template<typename... Args> inline auto operator()(Args... args) const
|
||||
{
|
||||
assert(kernel_info_.kernel);
|
||||
|
||||
return kernel_info_.kernel(args...);
|
||||
}
|
||||
|
||||
const char *get_uarch_name() const
|
||||
{
|
||||
return kernel_info_.uarch_name;
|
||||
}
|
||||
|
||||
protected:
|
||||
/* Helper class which allows to pass human-readable microarchitecture name together with function
|
||||
* pointer. */
|
||||
class KernelInfo {
|
||||
public:
|
||||
KernelInfo() : KernelInfo("", nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/* TODO(sergey): Use string view, to have higher-level functionality (i.e. comparison) without
|
||||
* memory allocation. */
|
||||
KernelInfo(const char *uarch_name, FunctionType kernel)
|
||||
: uarch_name(uarch_name), kernel(kernel)
|
||||
{
|
||||
}
|
||||
|
||||
const char *uarch_name;
|
||||
FunctionType kernel;
|
||||
};
|
||||
|
||||
KernelInfo get_best_kernel_info(FunctionType kernel_default,
|
||||
FunctionType kernel_sse2,
|
||||
FunctionType kernel_sse3,
|
||||
FunctionType kernel_sse41,
|
||||
FunctionType kernel_avx,
|
||||
FunctionType kernel_avx2)
|
||||
{
|
||||
/* Silence warnings about unused variables when compiling without some architectures. */
|
||||
(void)kernel_sse2;
|
||||
(void)kernel_sse3;
|
||||
(void)kernel_sse41;
|
||||
(void)kernel_avx;
|
||||
(void)kernel_avx2;
|
||||
|
||||
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
|
||||
if (DebugFlags().cpu.has_avx2() && system_cpu_support_avx2()) {
|
||||
return KernelInfo("AVX2", kernel_avx2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX
|
||||
if (DebugFlags().cpu.has_avx() && system_cpu_support_avx()) {
|
||||
return KernelInfo("AVX", kernel_avx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
|
||||
if (DebugFlags().cpu.has_sse41() && system_cpu_support_sse41()) {
|
||||
return KernelInfo("SSE4.1", kernel_sse41);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
|
||||
if (DebugFlags().cpu.has_sse3() && system_cpu_support_sse3()) {
|
||||
return KernelInfo("SSE3", kernel_sse3);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
|
||||
if (DebugFlags().cpu.has_sse2() && system_cpu_support_sse2()) {
|
||||
return KernelInfo("SSE2", kernel_sse2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return KernelInfo("default", kernel_default);
|
||||
}
|
||||
|
||||
KernelInfo kernel_info_;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
85
intern/cycles/device/cpu/kernel_thread_globals.cpp
Normal file
85
intern/cycles/device/cpu/kernel_thread_globals.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2011-2021 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "device/cpu/kernel_thread_globals.h"
|
||||
|
||||
// clang-format off
|
||||
#include "kernel/osl/osl_shader.h"
|
||||
#include "kernel/osl/osl_globals.h"
|
||||
// clang-format on
|
||||
|
||||
#include "util/util_profiling.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
CPUKernelThreadGlobals::CPUKernelThreadGlobals(const KernelGlobals &kernel_globals,
|
||||
void *osl_globals_memory,
|
||||
Profiler &cpu_profiler)
|
||||
: KernelGlobals(kernel_globals), cpu_profiler_(cpu_profiler)
|
||||
{
|
||||
reset_runtime_memory();
|
||||
|
||||
#ifdef WITH_OSL
|
||||
OSLShader::thread_init(this, reinterpret_cast<OSLGlobals *>(osl_globals_memory));
|
||||
#else
|
||||
(void)osl_globals_memory;
|
||||
#endif
|
||||
}
|
||||
|
||||
CPUKernelThreadGlobals::CPUKernelThreadGlobals(CPUKernelThreadGlobals &&other) noexcept
|
||||
: KernelGlobals(std::move(other)), cpu_profiler_(other.cpu_profiler_)
|
||||
{
|
||||
other.reset_runtime_memory();
|
||||
}
|
||||
|
||||
CPUKernelThreadGlobals::~CPUKernelThreadGlobals()
|
||||
{
|
||||
#ifdef WITH_OSL
|
||||
OSLShader::thread_free(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
CPUKernelThreadGlobals &CPUKernelThreadGlobals::operator=(CPUKernelThreadGlobals &&other)
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
*static_cast<KernelGlobals *>(this) = *static_cast<KernelGlobals *>(&other);
|
||||
|
||||
other.reset_runtime_memory();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CPUKernelThreadGlobals::reset_runtime_memory()
|
||||
{
|
||||
#ifdef WITH_OSL
|
||||
osl = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CPUKernelThreadGlobals::start_profiling()
|
||||
{
|
||||
cpu_profiler_.add_state(&profiler);
|
||||
}
|
||||
|
||||
void CPUKernelThreadGlobals::stop_profiling()
|
||||
{
|
||||
cpu_profiler_.remove_state(&profiler);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
57
intern/cycles/device/cpu/kernel_thread_globals.h
Normal file
57
intern/cycles/device/cpu/kernel_thread_globals.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2011-2021 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/device/cpu/compat.h"
|
||||
#include "kernel/device/cpu/globals.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class Profiler;
|
||||
|
||||
/* A special class which extends memory ownership of the `KernelGlobals` decoupling any resource
|
||||
* which is not thread-safe for access. Every worker thread which needs to operate on
|
||||
* `KernelGlobals` needs to initialize its own copy of this object.
|
||||
*
|
||||
* NOTE: Only minimal subset of objects are copied: `KernelData` is never copied. This means that
|
||||
* there is no unnecessary data duplication happening when using this object. */
|
||||
class CPUKernelThreadGlobals : public KernelGlobals {
|
||||
public:
|
||||
/* TODO(sergey): Would be nice to have properly typed OSLGlobals even in the case when building
|
||||
* without OSL support. Will avoid need to those unnamed pointers and casts. */
|
||||
CPUKernelThreadGlobals(const KernelGlobals &kernel_globals,
|
||||
void *osl_globals_memory,
|
||||
Profiler &cpu_profiler);
|
||||
|
||||
~CPUKernelThreadGlobals();
|
||||
|
||||
CPUKernelThreadGlobals(const CPUKernelThreadGlobals &other) = delete;
|
||||
CPUKernelThreadGlobals(CPUKernelThreadGlobals &&other) noexcept;
|
||||
|
||||
CPUKernelThreadGlobals &operator=(const CPUKernelThreadGlobals &other) = delete;
|
||||
CPUKernelThreadGlobals &operator=(CPUKernelThreadGlobals &&other);
|
||||
|
||||
void start_profiling();
|
||||
void stop_profiling();
|
||||
|
||||
protected:
|
||||
void reset_runtime_memory();
|
||||
|
||||
Profiler &cpu_profiler_;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
@@ -14,21 +14,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "device/cuda/device.h"
|
||||
|
||||
#include "util/util_logging.h"
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
|
||||
# include "device/cuda/device_cuda.h"
|
||||
# include "device/cuda/device_impl.h"
|
||||
# include "device/device.h"
|
||||
# include "device/device_intern.h"
|
||||
|
||||
# include "util/util_logging.h"
|
||||
# include "util/util_string.h"
|
||||
# include "util/util_windows.h"
|
||||
#endif /* WITH_CUDA */
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
bool device_cuda_init()
|
||||
{
|
||||
# ifdef WITH_CUDA_DYNLOAD
|
||||
#if !defined(WITH_CUDA)
|
||||
return false;
|
||||
#elif defined(WITH_CUDA_DYNLOAD)
|
||||
static bool initialized = false;
|
||||
static bool result = false;
|
||||
|
||||
@@ -59,16 +63,27 @@ bool device_cuda_init()
|
||||
}
|
||||
|
||||
return result;
|
||||
# else /* WITH_CUDA_DYNLOAD */
|
||||
#else /* WITH_CUDA_DYNLOAD */
|
||||
return true;
|
||||
# endif /* WITH_CUDA_DYNLOAD */
|
||||
#endif /* WITH_CUDA_DYNLOAD */
|
||||
}
|
||||
|
||||
Device *device_cuda_create(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background)
|
||||
Device *device_cuda_create(const DeviceInfo &info, Stats &stats, Profiler &profiler)
|
||||
{
|
||||
return new CUDADevice(info, stats, profiler, background);
|
||||
#ifdef WITH_CUDA
|
||||
return new CUDADevice(info, stats, profiler);
|
||||
#else
|
||||
(void)info;
|
||||
(void)stats;
|
||||
(void)profiler;
|
||||
|
||||
LOG(FATAL) << "Request to create CUDA device without compiled-in support. Should never happen.";
|
||||
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
static CUresult device_cuda_safe_init()
|
||||
{
|
||||
# ifdef _WIN32
|
||||
@@ -86,9 +101,11 @@ static CUresult device_cuda_safe_init()
|
||||
return cuInit(0);
|
||||
# endif
|
||||
}
|
||||
#endif /* WITH_CUDA */
|
||||
|
||||
void device_cuda_info(vector<DeviceInfo> &devices)
|
||||
{
|
||||
#ifdef WITH_CUDA
|
||||
CUresult result = device_cuda_safe_init();
|
||||
if (result != CUDA_SUCCESS) {
|
||||
if (result != CUDA_ERROR_NO_DEVICE)
|
||||
@@ -129,9 +146,9 @@ void device_cuda_info(vector<DeviceInfo> &devices)
|
||||
|
||||
info.has_half_images = (major >= 3);
|
||||
info.has_nanovdb = true;
|
||||
info.has_volume_decoupled = false;
|
||||
info.has_adaptive_stop_per_sample = false;
|
||||
info.denoisers = DENOISER_NLM;
|
||||
info.denoisers = 0;
|
||||
|
||||
info.has_gpu_queue = true;
|
||||
|
||||
/* Check if the device has P2P access to any other device in the system. */
|
||||
for (int peer_num = 0; peer_num < count && !info.has_peer_memory; peer_num++) {
|
||||
@@ -182,10 +199,14 @@ void device_cuda_info(vector<DeviceInfo> &devices)
|
||||
|
||||
if (!display_devices.empty())
|
||||
devices.insert(devices.end(), display_devices.begin(), display_devices.end());
|
||||
#else /* WITH_CUDA */
|
||||
(void)devices;
|
||||
#endif /* WITH_CUDA */
|
||||
}
|
||||
|
||||
string device_cuda_capabilities()
|
||||
{
|
||||
#ifdef WITH_CUDA
|
||||
CUresult result = device_cuda_safe_init();
|
||||
if (result != CUDA_SUCCESS) {
|
||||
if (result != CUDA_ERROR_NO_DEVICE) {
|
||||
@@ -310,8 +331,10 @@ string device_cuda_capabilities()
|
||||
}
|
||||
|
||||
return capabilities;
|
||||
|
||||
#else /* WITH_CUDA */
|
||||
return "";
|
||||
#endif /* WITH_CUDA */
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2017 Blender Foundation
|
||||
* Copyright 2011-2021 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,13 +14,24 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "kernel/kernel_compat_opencl.h"
|
||||
#include "kernel/split/kernel_split_common.h"
|
||||
#include "kernel/split/kernel_enqueue_inactive.h"
|
||||
#pragma once
|
||||
|
||||
#define KERNEL_NAME enqueue_inactive
|
||||
#define LOCALS_TYPE unsigned int
|
||||
#include "kernel/kernels/opencl/kernel_split_function.h"
|
||||
#undef KERNEL_NAME
|
||||
#undef LOCALS_TYPE
|
||||
#include "util/util_string.h"
|
||||
#include "util/util_vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class Device;
|
||||
class DeviceInfo;
|
||||
class Profiler;
|
||||
class Stats;
|
||||
|
||||
bool device_cuda_init();
|
||||
|
||||
Device *device_cuda_create(const DeviceInfo &info, Stats &stats, Profiler &profiler);
|
||||
|
||||
void device_cuda_info(vector<DeviceInfo> &devices);
|
||||
|
||||
string device_cuda_capabilities();
|
||||
|
||||
CCL_NAMESPACE_END
|
@@ -1,270 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2013 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
|
||||
# include "device/device.h"
|
||||
# include "device/device_denoising.h"
|
||||
# include "device/device_split_kernel.h"
|
||||
|
||||
# include "util/util_map.h"
|
||||
# include "util/util_task.h"
|
||||
|
||||
# ifdef WITH_CUDA_DYNLOAD
|
||||
# include "cuew.h"
|
||||
# else
|
||||
# include "util/util_opengl.h"
|
||||
# include <cuda.h>
|
||||
# include <cudaGL.h>
|
||||
# endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class CUDASplitKernel;
|
||||
|
||||
class CUDADevice : public Device {
|
||||
|
||||
friend class CUDASplitKernelFunction;
|
||||
friend class CUDASplitKernel;
|
||||
friend class CUDAContextScope;
|
||||
|
||||
public:
|
||||
DedicatedTaskPool task_pool;
|
||||
CUdevice cuDevice;
|
||||
CUcontext cuContext;
|
||||
CUmodule cuModule, cuFilterModule;
|
||||
size_t device_texture_headroom;
|
||||
size_t device_working_headroom;
|
||||
bool move_texture_to_host;
|
||||
size_t map_host_used;
|
||||
size_t map_host_limit;
|
||||
int can_map_host;
|
||||
int pitch_alignment;
|
||||
int cuDevId;
|
||||
int cuDevArchitecture;
|
||||
bool first_error;
|
||||
CUDASplitKernel *split_kernel;
|
||||
|
||||
struct CUDAMem {
|
||||
CUDAMem() : texobject(0), array(0), use_mapped_host(false)
|
||||
{
|
||||
}
|
||||
|
||||
CUtexObject texobject;
|
||||
CUarray array;
|
||||
|
||||
/* If true, a mapped host memory in shared_pointer is being used. */
|
||||
bool use_mapped_host;
|
||||
};
|
||||
typedef map<device_memory *, CUDAMem> CUDAMemMap;
|
||||
CUDAMemMap cuda_mem_map;
|
||||
thread_mutex cuda_mem_map_mutex;
|
||||
|
||||
struct PixelMem {
|
||||
GLuint cuPBO;
|
||||
CUgraphicsResource cuPBOresource;
|
||||
GLuint cuTexId;
|
||||
int w, h;
|
||||
};
|
||||
map<device_ptr, PixelMem> pixel_mem_map;
|
||||
|
||||
/* Bindless Textures */
|
||||
device_vector<TextureInfo> texture_info;
|
||||
bool need_texture_info;
|
||||
|
||||
/* Kernels */
|
||||
struct {
|
||||
bool loaded;
|
||||
|
||||
CUfunction adaptive_stopping;
|
||||
CUfunction adaptive_filter_x;
|
||||
CUfunction adaptive_filter_y;
|
||||
CUfunction adaptive_scale_samples;
|
||||
int adaptive_num_threads_per_block;
|
||||
} functions;
|
||||
|
||||
static bool have_precompiled_kernels();
|
||||
|
||||
virtual bool show_samples() const override;
|
||||
|
||||
virtual BVHLayoutMask get_bvh_layout_mask() const override;
|
||||
|
||||
void set_error(const string &error) override;
|
||||
|
||||
CUDADevice(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background_);
|
||||
|
||||
virtual ~CUDADevice();
|
||||
|
||||
bool support_device(const DeviceRequestedFeatures & /*requested_features*/);
|
||||
|
||||
bool check_peer_access(Device *peer_device) override;
|
||||
|
||||
bool use_adaptive_compilation();
|
||||
|
||||
bool use_split_kernel();
|
||||
|
||||
virtual string compile_kernel_get_common_cflags(
|
||||
const DeviceRequestedFeatures &requested_features, bool filter = false, bool split = false);
|
||||
|
||||
string compile_kernel(const DeviceRequestedFeatures &requested_features,
|
||||
const char *name,
|
||||
const char *base = "cuda",
|
||||
bool force_ptx = false);
|
||||
|
||||
virtual bool load_kernels(const DeviceRequestedFeatures &requested_features) override;
|
||||
|
||||
void load_functions();
|
||||
|
||||
void reserve_local_memory(const DeviceRequestedFeatures &requested_features);
|
||||
|
||||
void init_host_memory();
|
||||
|
||||
void load_texture_info();
|
||||
|
||||
void move_textures_to_host(size_t size, bool for_texture);
|
||||
|
||||
CUDAMem *generic_alloc(device_memory &mem, size_t pitch_padding = 0);
|
||||
|
||||
void generic_copy_to(device_memory &mem);
|
||||
|
||||
void generic_free(device_memory &mem);
|
||||
|
||||
void mem_alloc(device_memory &mem) override;
|
||||
|
||||
void mem_copy_to(device_memory &mem) override;
|
||||
|
||||
void mem_copy_from(device_memory &mem, int y, int w, int h, int elem) override;
|
||||
|
||||
void mem_zero(device_memory &mem) override;
|
||||
|
||||
void mem_free(device_memory &mem) override;
|
||||
|
||||
device_ptr mem_alloc_sub_ptr(device_memory &mem, int offset, int /*size*/) override;
|
||||
|
||||
virtual void const_copy_to(const char *name, void *host, size_t size) override;
|
||||
|
||||
void global_alloc(device_memory &mem);
|
||||
|
||||
void global_free(device_memory &mem);
|
||||
|
||||
void tex_alloc(device_texture &mem);
|
||||
|
||||
void tex_free(device_texture &mem);
|
||||
|
||||
bool denoising_non_local_means(device_ptr image_ptr,
|
||||
device_ptr guide_ptr,
|
||||
device_ptr variance_ptr,
|
||||
device_ptr out_ptr,
|
||||
DenoisingTask *task);
|
||||
|
||||
bool denoising_construct_transform(DenoisingTask *task);
|
||||
|
||||
bool denoising_accumulate(device_ptr color_ptr,
|
||||
device_ptr color_variance_ptr,
|
||||
device_ptr scale_ptr,
|
||||
int frame,
|
||||
DenoisingTask *task);
|
||||
|
||||
bool denoising_solve(device_ptr output_ptr, DenoisingTask *task);
|
||||
|
||||
bool denoising_combine_halves(device_ptr a_ptr,
|
||||
device_ptr b_ptr,
|
||||
device_ptr mean_ptr,
|
||||
device_ptr variance_ptr,
|
||||
int r,
|
||||
int4 rect,
|
||||
DenoisingTask *task);
|
||||
|
||||
bool denoising_divide_shadow(device_ptr a_ptr,
|
||||
device_ptr b_ptr,
|
||||
device_ptr sample_variance_ptr,
|
||||
device_ptr sv_variance_ptr,
|
||||
device_ptr buffer_variance_ptr,
|
||||
DenoisingTask *task);
|
||||
|
||||
bool denoising_get_feature(int mean_offset,
|
||||
int variance_offset,
|
||||
device_ptr mean_ptr,
|
||||
device_ptr variance_ptr,
|
||||
float scale,
|
||||
DenoisingTask *task);
|
||||
|
||||
bool denoising_write_feature(int out_offset,
|
||||
device_ptr from_ptr,
|
||||
device_ptr buffer_ptr,
|
||||
DenoisingTask *task);
|
||||
|
||||
bool denoising_detect_outliers(device_ptr image_ptr,
|
||||
device_ptr variance_ptr,
|
||||
device_ptr depth_ptr,
|
||||
device_ptr output_ptr,
|
||||
DenoisingTask *task);
|
||||
|
||||
void denoise(RenderTile &rtile, DenoisingTask &denoising);
|
||||
|
||||
void adaptive_sampling_filter(uint filter_sample,
|
||||
WorkTile *wtile,
|
||||
CUdeviceptr d_wtile,
|
||||
CUstream stream = 0);
|
||||
void adaptive_sampling_post(RenderTile &rtile,
|
||||
WorkTile *wtile,
|
||||
CUdeviceptr d_wtile,
|
||||
CUstream stream = 0);
|
||||
|
||||
void render(DeviceTask &task, RenderTile &rtile, device_vector<WorkTile> &work_tiles);
|
||||
|
||||
void film_convert(DeviceTask &task,
|
||||
device_ptr buffer,
|
||||
device_ptr rgba_byte,
|
||||
device_ptr rgba_half);
|
||||
|
||||
void shader(DeviceTask &task);
|
||||
|
||||
CUdeviceptr map_pixels(device_ptr mem);
|
||||
|
||||
void unmap_pixels(device_ptr mem);
|
||||
|
||||
void pixels_alloc(device_memory &mem);
|
||||
|
||||
void pixels_copy_from(device_memory &mem, int y, int w, int h);
|
||||
|
||||
void pixels_free(device_memory &mem);
|
||||
|
||||
void draw_pixels(device_memory &mem,
|
||||
int y,
|
||||
int w,
|
||||
int h,
|
||||
int width,
|
||||
int height,
|
||||
int dx,
|
||||
int dy,
|
||||
int dw,
|
||||
int dh,
|
||||
bool transparent,
|
||||
const DeviceDrawParams &draw_params) override;
|
||||
|
||||
void thread_run(DeviceTask &task);
|
||||
|
||||
virtual void task_add(DeviceTask &task) override;
|
||||
|
||||
virtual void task_wait() override;
|
||||
|
||||
virtual void task_cancel() override;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
1370
intern/cycles/device/cuda/device_impl.cpp
Normal file
1370
intern/cycles/device/cuda/device_impl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user