Compare commits
480 Commits
temp-exper
...
temp-nodes
Author | SHA1 | Date | |
---|---|---|---|
3b3908ce99 | |||
89484e9754 | |||
66f8835f9c | |||
3d3b6d94e6 | |||
66151b5de3 | |||
c1d0b234fb | |||
8d51c06611 | |||
20d0bb43af | |||
c51a5b204c | |||
26b5760d6d | |||
84671d796d | |||
b665781808 | |||
ed809866b1 | |||
e6aece32a0 | |||
74633c0456 | |||
![]() |
c399651637 | ||
c3a4c6c209 | |||
4935ed6ce6 | |||
dc8b31af57 | |||
f066cee92f | |||
548d8a397c | |||
2a8122fb65 | |||
0d9f79b163 | |||
f21de01b84 | |||
7909f70f64 | |||
e9e054b987 | |||
71a8e32dc0 | |||
d55d95b04d | |||
![]() |
7d2f746369 | ||
![]() |
6499a2ec5c | ||
d7a2e0b83c | |||
![]() |
be262cf561 | ||
![]() |
0734b235d2 | ||
ae1e68f514 | |||
70e064f111 | |||
c4f3475612 | |||
6249995c5e | |||
eaa726542e | |||
77f73a9284 | |||
a35c0fe6ce | |||
14f61c619b | |||
4fc54ddae1 | |||
1559aa3da0 | |||
![]() |
c134d7437d | ||
93e3aed041 | |||
aa030d3459 | |||
51c433f1a5 | |||
8a77019474 | |||
04f91bce53 | |||
b64f0fab06 | |||
2e67191c86 | |||
3656fc3aee | |||
2a81d948ad | |||
5c490bcbc8 | |||
ef6d652428 | |||
f226687bb9 | |||
4792d988fb | |||
e9a47223cb | |||
4bc7996e2e | |||
72a207de35 | |||
![]() |
601b690a24 | ||
![]() |
da2955fdf6 | ||
7a005fb7d1 | |||
dd2b616320 | |||
06fdbe6664 | |||
fba35a02c6 | |||
![]() |
5f2c5e5bb8 | ||
ebaa3fcedd | |||
7cb65a1e67 | |||
be8b60aa20 | |||
02404ded80 | |||
a0b85800ec | |||
3df2bea88b | |||
4d94e2afc8 | |||
2188047d9d | |||
52022cba78 | |||
![]() |
5f55022276 | ||
292685ea39 | |||
0cb264a282 | |||
17ac860cef | |||
32fd000b4b | |||
1ac3c861fd | |||
![]() |
5a1cef2e76 | ||
bf329d37da | |||
7a0281914e | |||
7f9ed0178a | |||
b90ccaa067 | |||
![]() |
5501a5de32 | ||
![]() |
d6bbcc4f66 | ||
6d21703e89 | |||
e16c786022 | |||
93c10797dc | |||
744fa41e7e | |||
77b51d4e58 | |||
6623d572aa | |||
9708aa6341 | |||
c5e409b013 | |||
850115531d | |||
652dd4e27f | |||
d1c6704413 | |||
cf6d17a6aa | |||
2fec46c3e6 | |||
c8d6e2dfa0 | |||
e90a2a3f01 | |||
f04206cbc7 | |||
e747c07156 | |||
b449da3a7d | |||
db15df0baa | |||
aa065a2951 | |||
d3506c86da | |||
9ad181a5d0 | |||
9c088b1b97 | |||
2b0d08961a | |||
de9977260c | |||
e9cd3d50a7 | |||
9f3c5a061d | |||
e77c65f73c | |||
bd4ed5ca9a | |||
ded9484925 | |||
aaa1d58054 | |||
90bcd5e724 | |||
a1f44e43a2 | |||
5d6e5a9076 | |||
e91b59b589 | |||
e845467d93 | |||
735093dee8 | |||
3469e06c1a | |||
bbe6d44928 | |||
131a758b6f | |||
be7106a974 | |||
7e32bb8492 | |||
226eb5e366 | |||
18e063b69d | |||
7a07ca1f8c | |||
644976548d | |||
9fbf3075ad | |||
2ba2d2bd9d | |||
7f96e6ed7e | |||
6ac0a3d83c | |||
ae4a430755 | |||
526373b897 | |||
cd8893d446 | |||
d179e1c6e4 | |||
0373d1b09f | |||
8eaea99d98 | |||
![]() |
927d099ec0 | ||
![]() |
cdf564277c | ||
3a9d43cf31 | |||
2469ddc1a9 | |||
c0bbb93b88 | |||
421c5127f4 | |||
295b21f56a | |||
ee5a4f41eb | |||
141f17eaf4 | |||
8d958fe685 | |||
1a30687c24 | |||
4f3fba2aa7 | |||
665eca85ba | |||
7b528b2a3a | |||
99e5d5ba21 | |||
e391ad7bbc | |||
b9e07c1e0b | |||
96fa78f5b0 | |||
ca475479eb | |||
41982af6a0 | |||
f24992d2ec | |||
b4b02eb4ff | |||
ceb500df03 | |||
425e706921 | |||
a92ebab5da | |||
b32e8e5ba7 | |||
cfd54ad7d7 | |||
9c4c3fbabc | |||
3fd92b5c22 | |||
f817a11dc6 | |||
1135790ad5 | |||
84702bd3d8 | |||
f4d07196bd | |||
aff7d59986 | |||
324d6d2192 | |||
649c87814d | |||
9237b2019c | |||
35f379ba26 | |||
793547e7d1 | |||
985bc08688 | |||
eb45e7be47 | |||
![]() |
cd4e27a4a1 | ||
011a79215d | |||
d7cfee0b68 | |||
b243fab16b | |||
eaf5ee8981 | |||
41a945d746 | |||
7b45850eac | |||
b303769d2e | |||
c60c30205d | |||
c07c110467 | |||
b33d839162 | |||
a823e825c8 | |||
0d599ce95a | |||
e12eb89f22 | |||
736b0d6894 | |||
1f691050e5 | |||
10d2cbfa36 | |||
1451f7d093 | |||
fc5f9a8ac9 | |||
4a09907eab | |||
6a8f4bfc60 | |||
b01c865687 | |||
87db3423c9 | |||
![]() |
a73dfac519 | ||
![]() |
9425628c84 | ||
f2988543c2 | |||
8e5b6320a6 | |||
![]() |
685419d6be | ||
91bf24dd00 | |||
f0ab9034d9 | |||
aee7d8f411 | |||
e69034e6d9 | |||
c082b21625 | |||
160d8c1ea6 | |||
fad8a753a9 | |||
2c31a84bd1 | |||
1db904d954 | |||
74c6c504b2 | |||
908b383b7d | |||
9f337bef80 | |||
8bd5d58860 | |||
255c850e0b | |||
b2a6e2abdb | |||
69d30c1543 | |||
41d1729148 | |||
6f47549fe5 | |||
c7f6309437 | |||
b2037464e4 | |||
be970c03c2 | |||
d3fe320b83 | |||
0706a756f9 | |||
6290091bac | |||
da6dea5701 | |||
694032c9d1 | |||
c2e6969c56 | |||
bc95c249a7 | |||
bcdba7c34d | |||
02a63115d2 | |||
c371d699ca | |||
7d114e5d87 | |||
36f0a1ead7 | |||
b39ee69789 | |||
d311a76931 | |||
c3207d88c2 | |||
40e089716b | |||
05179a0ba4 | |||
8b777ee6d6 | |||
9a32c7130b | |||
d60b128274 | |||
a9203e25a2 | |||
089cd25982 | |||
a86bb2594f | |||
df2ed1550d | |||
1cc54107a9 | |||
d26588268d | |||
418cd7c4ba | |||
e25f7e33ff | |||
94e9d3ca3e | |||
d31dd1da80 | |||
2fa7e81d9c | |||
d144337098 | |||
58e554a55c | |||
09c7c63890 | |||
4b4aec2884 | |||
bfa083f873 | |||
40d6ee5304 | |||
b5c3f26cba | |||
f17b26bbed | |||
0ac8fec3be | |||
0ca0d3366d | |||
f508292277 | |||
5e0ef4ef85 | |||
0145c8d484 | |||
0d8948387e | |||
ce0f212498 | |||
4fde594fda | |||
023ebb890b | |||
1c2b203795 | |||
a1fb3dc7ae | |||
3584f1d224 | |||
b4530deec4 | |||
e061bbadec | |||
dfdf79fb03 | |||
95af2e39f6 | |||
9f2271d354 | |||
6251eb8bda | |||
![]() |
c85317e669 | ||
![]() |
f7a5695676 | ||
4ef0654449 | |||
502eadb2f7 | |||
ced673c833 | |||
9fb755fe4c | |||
2ee2f87f29 | |||
06da6e2eaf | |||
5f9358a373 | |||
14bb9f09ab | |||
54c28e5bfb | |||
ca476a638c | |||
66a87fc9f4 | |||
1e8ed36a90 | |||
![]() |
6fb7d0f559 | ||
4e8c78245d | |||
24cdffde55 | |||
f5ec29023d | |||
e02d84eb3b | |||
0a44c4b594 | |||
1e193a0b56 | |||
79dd9fedb2 | |||
3cc1bcce4f | |||
7573631d69 | |||
d4ffccbeae | |||
3adb9530bb | |||
3856c58f5d | |||
6403c8c025 | |||
39b752316d | |||
66161ba3a1 | |||
f7829961c6 | |||
ecffd231a0 | |||
fef7b792e7 | |||
cdfa3feb91 | |||
c4bbe44e47 | |||
2f0d919f89 | |||
8fd3ffcb31 | |||
27c142aa29 | |||
a8436334bd | |||
957de39191 | |||
![]() |
f71a7d3914 | ||
fa817b8c96 | |||
de60dc84e2 | |||
bf7fdd0f67 | |||
2aa7bc06e7 | |||
ce317c9faa | |||
f1a577b38a | |||
dc69ef6f3b | |||
5cf04fe2ba | |||
319056679b | |||
69a7015e12 | |||
3459f75f5b | |||
0b0e45252b | |||
237e27e161 | |||
20a54347ee | |||
3732508c64 | |||
c4286ddb09 | |||
![]() |
340529a845 | ||
df96a9c6ea | |||
c63442d2f2 | |||
cab6d5e94a | |||
6c840a2cb9 | |||
a51584dc70 | |||
04572f0899 | |||
dc59955481 | |||
f03752b92f | |||
10ce2a1016 | |||
32e4ded24b | |||
09709a7e64 | |||
b75552ebbb | |||
40d391fa60 | |||
![]() |
7a4bdc3a4f | ||
![]() |
0f2ae614a1 | ||
30dd31a7b3 | |||
33a558bf21 | |||
5c1b740f1e | |||
0815e2fdb1 | |||
406d747695 | |||
9131c697dd | |||
e5ee7e9a2d | |||
8795514384 | |||
8ed7ed0255 | |||
53bd58993e | |||
3cc7e2ad9d | |||
![]() |
74f6b81c12 | ||
4e90266fd8 | |||
6704372f04 | |||
10423d462a | |||
6f28c199b3 | |||
a0029a678f | |||
8cdd701b45 | |||
442b6e5e09 | |||
9e038a2c6b | |||
4b1112c8c9 | |||
5cf87b4a8e | |||
ab536824a6 | |||
4b0871af87 | |||
![]() |
3191b76eb5 | ||
024ac9c089 | |||
e7c36ce43c | |||
3e4dd7b000 | |||
a4226a050b | |||
646f1cc89a | |||
f64746177f | |||
0876829e7a | |||
5804bf25bd | |||
c13383da41 | |||
01b9dfeab4 | |||
73169628a1 | |||
b6aa8daf49 | |||
c4c2c4bdb8 | |||
cf9709fd1e | |||
21b9231d7f | |||
00b2c7c5cc | |||
9dab489d51 | |||
08ee5573a9 | |||
09fe0e8aa9 | |||
d08ec3120f | |||
84c08748d8 | |||
a60e270efb | |||
8ad305382e | |||
5d826866a3 | |||
cfc9b95abd | |||
1f4c1c5fc7 | |||
bae4d00e2a | |||
7d749720ad | |||
8df0268e2b | |||
80578a9d54 | |||
2771dfd563 | |||
ad4202a14f | |||
89f490932f | |||
![]() |
55c56f1ffb | ||
5f411f7f38 | |||
![]() |
78011d712d | ||
d985751324 | |||
ed1042ee06 | |||
76fd41e9db | |||
0f95f51361 | |||
2cd091e9c7 | |||
![]() |
dc170a6d67 | ||
8964c02348 | |||
8185d07ace | |||
38df935c09 | |||
aed5b88ec1 | |||
![]() |
27b78c9c94 | ||
614bd239f8 | |||
7b68d0679e | |||
7af8271c34 | |||
ba44919601 | |||
0b711e6758 | |||
3f7c294a95 | |||
97a6b3ceee | |||
37c5552742 | |||
![]() |
5d99199880 | ||
92826a921c | |||
bc58425862 | |||
b9e02eace6 | |||
6b5e4ad589 | |||
719bea0d6d | |||
![]() |
6c15b70279 | ||
bf5d45fd99 | |||
abbc43e4e4 | |||
957e292c58 | |||
c3b68fa7b1 | |||
c96d596f43 | |||
b2ad52a763 | |||
e0a4b392f3 | |||
28b17ef0e6 | |||
3b77bd48f9 | |||
3a254b93fd | |||
58dae919e5 | |||
![]() |
f5c0ef52cf | ||
c56da67716 | |||
26fd55fad1 | |||
1dc9650d20 | |||
89ae4a7a2a | |||
![]() |
401279253e | ||
![]() |
2a23addf52 | ||
ff51afb194 | |||
55059af01d | |||
![]() |
acbda123ad | ||
b9b59aa6de | |||
![]() |
688e5c6d38 | ||
b70f4a265a | |||
![]() |
d5c59913de | ||
ecdbd83a8d | |||
5bd822dc46 | |||
2a8b987e9e |
@@ -88,7 +88,6 @@ class VersionInfo:
|
||||
self.short_version = "%d.%02d" % (version_numbers[0], version_numbers[1])
|
||||
self.version = "%d.%02d.%d" % version_numbers
|
||||
self.version_cycle = self._parse_header_file(blender_h, 'BLENDER_VERSION_CYCLE')
|
||||
self.version_cycle_number = self._parse_header_file(blender_h, 'BLENDER_VERSION_CYCLE_NUMBER')
|
||||
self.hash = self._parse_header_file(buildinfo_h, 'BUILD_HASH')[1:-1]
|
||||
|
||||
if self.version_cycle == "release":
|
||||
@@ -97,8 +96,7 @@ class VersionInfo:
|
||||
self.is_development_build = False
|
||||
elif self.version_cycle == "rc":
|
||||
# Release candidate
|
||||
version_cycle = self.version_cycle + self.version_cycle_number
|
||||
self.full_version = self.version + version_cycle
|
||||
self.full_version = self.version + self.version_cycle
|
||||
self.is_development_build = False
|
||||
else:
|
||||
# Development build
|
||||
|
@@ -42,7 +42,7 @@ def get_cmake_options(builder):
|
||||
elif builder.platform == 'linux':
|
||||
config_file = "build_files/buildbot/config/blender_linux.cmake"
|
||||
|
||||
optix_sdk_dir = os.path.join(builder.blender_dir, '..', '..', 'NVIDIA-Optix-SDK')
|
||||
optix_sdk_dir = os.path.join(builder.blender_dir, '..', '..', 'NVIDIA-Optix-SDK-7.1')
|
||||
options.append('-DOPTIX_ROOT_DIR:PATH=' + optix_sdk_dir)
|
||||
|
||||
# Workaround to build sm_30 kernels with CUDA 10, since CUDA 11 no longer supports that architecture
|
||||
|
@@ -20,6 +20,8 @@
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
# Note: this code should be cleaned up / refactored.
|
||||
|
||||
import sys
|
||||
if sys.version_info.major < 3:
|
||||
print("\nPython3.x needed, found %s.\nAborting!\n" %
|
||||
@@ -37,12 +39,23 @@ from cmake_consistency_check_config import (
|
||||
|
||||
|
||||
import os
|
||||
from os.path import join, dirname, normpath, splitext
|
||||
from os.path import (
|
||||
dirname,
|
||||
join,
|
||||
normpath,
|
||||
splitext,
|
||||
)
|
||||
|
||||
global_h = set()
|
||||
global_c = set()
|
||||
global_refs = {}
|
||||
|
||||
# Flatten `IGNORE_SOURCE_MISSING` to avoid nested looping.
|
||||
IGNORE_SOURCE_MISSING = [
|
||||
(k, ignore_path) for k, ig_list in IGNORE_SOURCE_MISSING
|
||||
for ignore_path in ig_list
|
||||
]
|
||||
|
||||
# Ignore cmake file, path pairs.
|
||||
global_ignore_source_missing = {}
|
||||
for k, v in IGNORE_SOURCE_MISSING:
|
||||
@@ -178,6 +191,8 @@ def cmake_get_src(f):
|
||||
|
||||
if not l:
|
||||
pass
|
||||
elif l in local_ignore_source_missing:
|
||||
local_ignore_source_missing.remove(l)
|
||||
elif l.startswith("$"):
|
||||
if context_name == "SRC":
|
||||
# assume if it ends with context_name we know about it
|
||||
@@ -227,10 +242,7 @@ def cmake_get_src(f):
|
||||
# replace_line(f, i - 1, new_path_rel)
|
||||
|
||||
else:
|
||||
if l in local_ignore_source_missing:
|
||||
local_ignore_source_missing.remove(l)
|
||||
else:
|
||||
raise Exception("non existent include %s:%d -> %s" % (f, i, new_file))
|
||||
raise Exception("non existent include %s:%d -> %s" % (f, i, new_file))
|
||||
|
||||
# print(new_file)
|
||||
|
||||
@@ -258,16 +270,16 @@ def cmake_get_src(f):
|
||||
|
||||
|
||||
def is_ignore_source(f, ignore_used):
|
||||
for index, ig in enumerate(IGNORE_SOURCE):
|
||||
if ig in f:
|
||||
for index, ignore_path in enumerate(IGNORE_SOURCE):
|
||||
if ignore_path in f:
|
||||
ignore_used[index] = True
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_ignore_cmake(f, ignore_used):
|
||||
for index, ig in enumerate(IGNORE_CMAKE):
|
||||
if ig in f:
|
||||
for index, ignore_path in enumerate(IGNORE_CMAKE):
|
||||
if ignore_path in f:
|
||||
ignore_used[index] = True
|
||||
return True
|
||||
return False
|
||||
@@ -298,7 +310,7 @@ def main():
|
||||
for cf, i in refs:
|
||||
errs.append((cf, i))
|
||||
else:
|
||||
raise Exception("CMake referenecs missing, internal error, aborting!")
|
||||
raise Exception("CMake references missing, internal error, aborting!")
|
||||
is_err = True
|
||||
|
||||
errs.sort()
|
||||
@@ -309,7 +321,7 @@ def main():
|
||||
# print("sed '%dd' '%s' > '%s.tmp' ; mv '%s.tmp' '%s'" % (i, cf, cf, cf, cf))
|
||||
|
||||
if is_err:
|
||||
raise Exception("CMake referenecs missing files, aborting!")
|
||||
raise Exception("CMake references missing files, aborting!")
|
||||
del is_err
|
||||
del errs
|
||||
|
||||
@@ -320,7 +332,7 @@ def main():
|
||||
if cf not in global_c:
|
||||
print("missing_c: ", cf)
|
||||
|
||||
# check if automake builds a corrasponding .o file.
|
||||
# Check if automake builds a corresponding .o file.
|
||||
'''
|
||||
if cf in global_c:
|
||||
out1 = os.path.splitext(cf)[0] + ".o"
|
||||
@@ -356,21 +368,21 @@ def main():
|
||||
|
||||
# Check ignores aren't stale
|
||||
print("\nCheck for unused 'IGNORE_SOURCE' paths...")
|
||||
for index, ig in enumerate(IGNORE_SOURCE):
|
||||
for index, ignore_path in enumerate(IGNORE_SOURCE):
|
||||
if not ignore_used_source[index]:
|
||||
print("unused ignore: %r" % ig)
|
||||
print("unused ignore: %r" % ignore_path)
|
||||
|
||||
# Check ignores aren't stale
|
||||
print("\nCheck for unused 'IGNORE_SOURCE_MISSING' paths...")
|
||||
for k, v in sorted(global_ignore_source_missing.items()):
|
||||
for ig in v:
|
||||
print("unused ignore: %r -> %r" % (ig, k))
|
||||
for ignore_path in v:
|
||||
print("unused ignore: %r -> %r" % (ignore_path, k))
|
||||
|
||||
# Check ignores aren't stale
|
||||
print("\nCheck for unused 'IGNORE_CMAKE' paths...")
|
||||
for index, ig in enumerate(IGNORE_CMAKE):
|
||||
for index, ignore_path in enumerate(IGNORE_CMAKE):
|
||||
if not ignore_used_cmake[index]:
|
||||
print("unused ignore: %r" % ig)
|
||||
print("unused ignore: %r" % ignore_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@@ -34,8 +34,18 @@ IGNORE_SOURCE = (
|
||||
|
||||
# Ignore cmake file, path pairs.
|
||||
IGNORE_SOURCE_MISSING = (
|
||||
# Use for cycles stand-alone.
|
||||
("intern/cycles/util/CMakeLists.txt", "../../third_party/numaapi/include"),
|
||||
( # Use for cycles stand-alone.
|
||||
"intern/cycles/util/CMakeLists.txt", (
|
||||
"../../third_party/numaapi/include",
|
||||
)),
|
||||
( # Use for `WITH_NANOVDB`.
|
||||
"intern/cycles/kernel/CMakeLists.txt", (
|
||||
"nanovdb/util/CSampleFromVoxels.h",
|
||||
"nanovdb/util/SampleFromVoxels.h",
|
||||
"nanovdb/NanoVDB.h",
|
||||
"nanovdb/CNanoVDB.h",
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
IGNORE_CMAKE = (
|
||||
|
@@ -1231,7 +1231,7 @@ function(find_python_package
|
||||
set(WITH_PYTHON_INSTALL_${_upper_package} OFF PARENT_SCOPE)
|
||||
else()
|
||||
message(STATUS "${package} found at '${PYTHON_${_upper_package}_PATH}'")
|
||||
|
||||
|
||||
if(NOT "${relative_include_dir}" STREQUAL "")
|
||||
set(_relative_include_dir "${package}/${relative_include_dir}")
|
||||
unset(PYTHON_${_upper_package}_INCLUDE_DIRS CACHE)
|
||||
|
@@ -610,7 +610,13 @@ endif()
|
||||
|
||||
# GNU Compiler
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
|
||||
# ffp-contract=off:
|
||||
# Automatically turned on when building with "-march=native". This is
|
||||
# explicitly turned off here as it will make floating point math give a bit
|
||||
# different results. This will lead to automated test failures. So disable
|
||||
# this until we support it. Seems to default to off in clang and the intel
|
||||
# compiler.
|
||||
set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -ffp-contract=off")
|
||||
|
||||
# `maybe-uninitialized` is unreliable in release builds, but fine in debug builds.
|
||||
set(GCC_EXTRA_FLAGS_RELEASE "-Wno-maybe-uninitialized")
|
||||
|
@@ -38,7 +38,7 @@ PROJECT_NAME = Blender
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "V2.92"
|
||||
PROJECT_NUMBER = "V2.93"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
16
extern/mantaflow/preprocessed/conjugategrad.h
vendored
16
extern/mantaflow/preprocessed/conjugategrad.h
vendored
@@ -170,7 +170,7 @@ struct ApplyMatrix : public KernelBase {
|
||||
unusedParameter(vecRhs); // Not needed in this matrix application
|
||||
|
||||
if (matrixA.size() != 4)
|
||||
errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step");
|
||||
errMsg("ConjugateGrad: Invalid A matrix in apply matrix step");
|
||||
Grid<Real> &A0 = *matrixA[0];
|
||||
Grid<Real> &Ai = *matrixA[1];
|
||||
Grid<Real> &Aj = *matrixA[2];
|
||||
@@ -256,7 +256,7 @@ struct ApplyMatrix2D : public KernelBase {
|
||||
unusedParameter(vecRhs); // Not needed in this matrix application
|
||||
|
||||
if (matrixA.size() != 3)
|
||||
errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step");
|
||||
errMsg("ConjugateGrad: Invalid A matrix in apply matrix step");
|
||||
Grid<Real> &A0 = *matrixA[0];
|
||||
Grid<Real> &Ai = *matrixA[1];
|
||||
Grid<Real> &Aj = *matrixA[2];
|
||||
@@ -338,7 +338,7 @@ struct ApplyMatrixViscosityU : public KernelBase {
|
||||
const std::vector<Grid<Real> *> vecRhs) const
|
||||
{
|
||||
if (matrixA.size() != 15)
|
||||
errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step");
|
||||
errMsg("ConjugateGrad: Invalid A matrix in apply matrix step");
|
||||
Grid<Real> &A0 = *matrixA[0];
|
||||
Grid<Real> &Aplusi = *matrixA[1];
|
||||
Grid<Real> &Aplusj = *matrixA[2];
|
||||
@@ -348,7 +348,7 @@ struct ApplyMatrixViscosityU : public KernelBase {
|
||||
Grid<Real> &Aminusk = *matrixA[6];
|
||||
|
||||
if (vecRhs.size() != 2)
|
||||
errMsg("ConjugatedGrad: Invalid rhs vector in apply matrix step");
|
||||
errMsg("ConjugateGrad: Invalid rhs vector in apply matrix step");
|
||||
Grid<Real> &srcV = *vecRhs[0];
|
||||
Grid<Real> &srcW = *vecRhs[1];
|
||||
|
||||
@@ -450,7 +450,7 @@ struct ApplyMatrixViscosityV : public KernelBase {
|
||||
const std::vector<Grid<Real> *> vecRhs) const
|
||||
{
|
||||
if (matrixA.size() != 15)
|
||||
errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step");
|
||||
errMsg("ConjugateGrad: Invalid A matrix in apply matrix step");
|
||||
Grid<Real> &A0 = *matrixA[0];
|
||||
Grid<Real> &Aplusi = *matrixA[1];
|
||||
Grid<Real> &Aplusj = *matrixA[2];
|
||||
@@ -460,7 +460,7 @@ struct ApplyMatrixViscosityV : public KernelBase {
|
||||
Grid<Real> &Aminusk = *matrixA[6];
|
||||
|
||||
if (vecRhs.size() != 2)
|
||||
errMsg("ConjugatedGrad: Invalid rhs vector in apply matrix step");
|
||||
errMsg("ConjugateGrad: Invalid rhs vector in apply matrix step");
|
||||
Grid<Real> &srcU = *vecRhs[0];
|
||||
Grid<Real> &srcW = *vecRhs[1];
|
||||
|
||||
@@ -562,7 +562,7 @@ struct ApplyMatrixViscosityW : public KernelBase {
|
||||
const std::vector<Grid<Real> *> vecRhs) const
|
||||
{
|
||||
if (matrixA.size() != 15)
|
||||
errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step");
|
||||
errMsg("ConjugateGrad: Invalid A matrix in apply matrix step");
|
||||
Grid<Real> &A0 = *matrixA[0];
|
||||
Grid<Real> &Aplusi = *matrixA[1];
|
||||
Grid<Real> &Aplusj = *matrixA[2];
|
||||
@@ -572,7 +572,7 @@ struct ApplyMatrixViscosityW : public KernelBase {
|
||||
Grid<Real> &Aminusk = *matrixA[6];
|
||||
|
||||
if (vecRhs.size() != 2)
|
||||
errMsg("ConjugatedGrad: Invalid rhs vector in apply matrix step");
|
||||
errMsg("ConjugateGrad: Invalid rhs vector in apply matrix step");
|
||||
Grid<Real> &srcU = *vecRhs[0];
|
||||
Grid<Real> &srcV = *vecRhs[1];
|
||||
|
||||
|
@@ -139,7 +139,7 @@ struct KnEstimateVolumeFraction : public KernelBase {
|
||||
{
|
||||
const Vec3 centre = startCentre + Vec3(i, j, k) * 0.5;
|
||||
const Real offset = 0.5 * dx;
|
||||
const int order = 2;
|
||||
const int order = 1; // is sufficient
|
||||
|
||||
Real phi000 = phi.getInterpolatedHi(centre + Vec3(-offset, -offset, -offset), order);
|
||||
Real phi001 = phi.getInterpolatedHi(centre + Vec3(-offset, -offset, +offset), order);
|
||||
@@ -1067,10 +1067,8 @@ void solveViscosity(const FlagGrid &flags,
|
||||
|
||||
Real viscTop = 0.25 * (viscosity(i, j, k) + viscosity(i, j, k - 1) + viscosity(i, j + 1, k) +
|
||||
viscosity(i, j + 1, k - 1));
|
||||
;
|
||||
Real viscBottom = 0.25 * (viscosity(i, j, k) + viscosity(i, j, k - 1) +
|
||||
viscosity(i, j - 1, k) + viscosity(i, j - 1, k - 1));
|
||||
;
|
||||
Real volTop = exVolLiquid(i, j + 1, k);
|
||||
Real volBottom = exVolLiquid(i, j, k);
|
||||
|
||||
@@ -1224,7 +1222,7 @@ void solveViscosity(const FlagGrid &flags,
|
||||
uSolution, uRhs, uResidual, uSearch, flags, uTmp, uMatA, uVecRhs);
|
||||
}
|
||||
else {
|
||||
errMsg("2D Matrix application not yet supported in viscosity solver");
|
||||
errMsg("Viscosity: 2D Matrix application not yet supported in viscosity solver");
|
||||
}
|
||||
|
||||
// CG solver for V
|
||||
@@ -1249,7 +1247,7 @@ void solveViscosity(const FlagGrid &flags,
|
||||
vSolution, vRhs, vResidual, vSearch, flags, vTmp, vMatA, vVecRhs);
|
||||
}
|
||||
else {
|
||||
errMsg("2D Matrix application not yet supported in viscosity solver");
|
||||
errMsg("Viscosity: 2D Matrix application not yet supported in viscosity solver");
|
||||
}
|
||||
|
||||
// CG solver for W
|
||||
@@ -1274,7 +1272,7 @@ void solveViscosity(const FlagGrid &flags,
|
||||
wSolution, wRhs, wResidual, wSearch, flags, wTmp, wMatA, wVecRhs);
|
||||
}
|
||||
else {
|
||||
errMsg("2D Matrix application not yet supported in viscosity solver");
|
||||
errMsg("Viscosity: 2D Matrix application not yet supported in viscosity solver");
|
||||
}
|
||||
|
||||
// Same accuracy for all dimensions
|
||||
@@ -1308,7 +1306,7 @@ void solveViscosity(const FlagGrid &flags,
|
||||
wRhs.copyFrom(wSearch);
|
||||
}
|
||||
debMsg(
|
||||
"Viscosity::solveViscosity done. "
|
||||
"Viscosity: solveViscosity() done. "
|
||||
"Iterations (u,v,w): ("
|
||||
<< uGcg->getIterations() << "," << vGcg->getIterations() << "," << wGcg->getIterations()
|
||||
<< "), "
|
||||
|
@@ -379,6 +379,9 @@ endif()
|
||||
# Subdirectories
|
||||
|
||||
if(WITH_CYCLES_BLENDER)
|
||||
# Not needed to make cycles automated tests pass with -march=native.
|
||||
# However Blender itself needs this flag.
|
||||
remove_cc_flag("-ffp-contract=off")
|
||||
add_definitions(-DWITH_BLENDER_GUARDEDALLOC)
|
||||
add_subdirectory(blender)
|
||||
endif()
|
||||
|
@@ -1148,7 +1148,7 @@ class CYCLES_PT_context_material(CyclesButtonsPanel, Panel):
|
||||
split = layout.split(factor=0.65)
|
||||
|
||||
if ob:
|
||||
split.template_ID(ob, "active_material", new="material.new", duplicate="material.duplicate")
|
||||
split.template_ID(ob, "active_material", new="material.new")
|
||||
row = split.row()
|
||||
|
||||
if slot:
|
||||
|
@@ -67,11 +67,10 @@ static bool ObtainCacheParticleData(
|
||||
Transform tfm = get_transform(b_ob->matrix_world());
|
||||
Transform itfm = transform_quick_inverse(tfm);
|
||||
|
||||
BL::Object::modifiers_iterator b_mod;
|
||||
for (b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
|
||||
if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) &&
|
||||
(background ? b_mod->show_render() : b_mod->show_viewport())) {
|
||||
BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
|
||||
for (BL::Modifier &b_mod : b_ob->modifiers) {
|
||||
if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
|
||||
(background ? b_mod.show_render() : b_mod.show_viewport())) {
|
||||
BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
|
||||
BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
|
||||
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
|
||||
|
||||
@@ -163,11 +162,10 @@ static bool ObtainCacheParticleUV(Hair *hair,
|
||||
|
||||
CData->curve_uv.clear();
|
||||
|
||||
BL::Object::modifiers_iterator b_mod;
|
||||
for (b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
|
||||
if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) &&
|
||||
(background ? b_mod->show_render() : b_mod->show_viewport())) {
|
||||
BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
|
||||
for (BL::Modifier &b_mod : b_ob->modifiers) {
|
||||
if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
|
||||
(background ? b_mod.show_render() : b_mod.show_viewport())) {
|
||||
BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
|
||||
BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
|
||||
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
|
||||
|
||||
@@ -226,11 +224,10 @@ static bool ObtainCacheParticleVcol(Hair *hair,
|
||||
|
||||
CData->curve_vcol.clear();
|
||||
|
||||
BL::Object::modifiers_iterator b_mod;
|
||||
for (b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
|
||||
if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) &&
|
||||
(background ? b_mod->show_render() : b_mod->show_viewport())) {
|
||||
BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
|
||||
for (BL::Modifier &b_mod : b_ob->modifiers) {
|
||||
if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
|
||||
(background ? b_mod.show_render() : b_mod.show_viewport())) {
|
||||
BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
|
||||
BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
|
||||
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
|
||||
|
||||
@@ -510,11 +507,10 @@ static void ExportCurveSegmentsMotion(Hair *hair, ParticleCurveData *CData, int
|
||||
bool BlenderSync::object_has_particle_hair(BL::Object b_ob)
|
||||
{
|
||||
/* Test if the object has a particle modifier with hair. */
|
||||
BL::Object::modifiers_iterator b_mod;
|
||||
for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
|
||||
if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) &&
|
||||
(preview ? b_mod->show_viewport() : b_mod->show_render())) {
|
||||
BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
|
||||
for (BL::Modifier &b_mod : b_ob.modifiers) {
|
||||
if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
|
||||
(preview ? b_mod.show_viewport() : b_mod.show_render())) {
|
||||
BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
|
||||
BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
|
||||
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
|
||||
|
||||
@@ -678,9 +674,7 @@ static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
|
||||
/* Export curves and points. */
|
||||
vector<float> points_length;
|
||||
|
||||
BL::Hair::curves_iterator b_curve_iter;
|
||||
for (b_hair.curves.begin(b_curve_iter); b_curve_iter != b_hair.curves.end(); ++b_curve_iter) {
|
||||
BL::HairCurve b_curve = *b_curve_iter;
|
||||
for (BL::HairCurve &b_curve : b_hair.curves) {
|
||||
const int first_point_index = b_curve.first_point_index();
|
||||
const int num_points = b_curve.num_points();
|
||||
|
||||
@@ -748,9 +742,7 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st
|
||||
int num_motion_keys = 0;
|
||||
int curve_index = 0;
|
||||
|
||||
BL::Hair::curves_iterator b_curve_iter;
|
||||
for (b_hair.curves.begin(b_curve_iter); b_curve_iter != b_hair.curves.end(); ++b_curve_iter) {
|
||||
BL::HairCurve b_curve = *b_curve_iter;
|
||||
for (BL::HairCurve &b_curve : b_hair.curves) {
|
||||
const int first_point_index = b_curve.first_point_index();
|
||||
const int num_points = b_curve.num_points();
|
||||
|
||||
@@ -855,10 +847,7 @@ void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *ha
|
||||
hair->set_value(socket, new_hair, socket);
|
||||
}
|
||||
|
||||
hair->attributes.clear();
|
||||
foreach (Attribute &attr, new_hair.attributes.attributes) {
|
||||
hair->attributes.attributes.push_back(std::move(attr));
|
||||
}
|
||||
hair->attributes.update(std::move(new_hair.attributes));
|
||||
|
||||
/* tag update */
|
||||
|
||||
|
@@ -47,11 +47,9 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
|
||||
|
||||
/* Find cycles preferences. */
|
||||
PointerRNA cpreferences;
|
||||
BL::Preferences::addons_iterator b_addon_iter;
|
||||
for (b_preferences.addons.begin(b_addon_iter); b_addon_iter != b_preferences.addons.end();
|
||||
++b_addon_iter) {
|
||||
if (b_addon_iter->module() == "cycles") {
|
||||
cpreferences = b_addon_iter->preferences().ptr;
|
||||
for (BL::Addon &b_addon : b_preferences.addons) {
|
||||
if (b_addon.module() == "cycles") {
|
||||
cpreferences = b_addon.preferences().ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -42,32 +42,20 @@ static Geometry::Type determine_geom_type(BL::Object &b_ob, bool use_particle_ha
|
||||
return Geometry::MESH;
|
||||
}
|
||||
|
||||
Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
BL::Object &b_ob,
|
||||
BL::Object &b_ob_instance,
|
||||
bool object_updated,
|
||||
bool use_particle_hair,
|
||||
TaskPool *task_pool)
|
||||
array<Node *> BlenderSync::find_used_shaders(BL::Object &b_ob)
|
||||
{
|
||||
/* 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;
|
||||
BL::Material material_override = view_layer.material_override;
|
||||
Shader *default_shader = (b_ob.type() == BL::Object::type_VOLUME) ? scene->default_volume :
|
||||
scene->default_surface;
|
||||
Geometry::Type geom_type = determine_geom_type(b_ob, use_particle_hair);
|
||||
GeometryKey key(b_key_id.ptr.data, geom_type);
|
||||
|
||||
/* Find shader indices. */
|
||||
array<Node *> used_shaders;
|
||||
|
||||
BL::Object::material_slots_iterator slot;
|
||||
for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
|
||||
for (BL::MaterialSlot &b_slot : b_ob.material_slots) {
|
||||
if (material_override) {
|
||||
find_shader(material_override, used_shaders, default_shader);
|
||||
}
|
||||
else {
|
||||
BL::ID b_material(slot->material());
|
||||
BL::ID b_material(b_slot.material());
|
||||
find_shader(b_material, used_shaders, default_shader);
|
||||
}
|
||||
}
|
||||
@@ -79,6 +67,25 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
used_shaders.push_back_slow(default_shader);
|
||||
}
|
||||
|
||||
return used_shaders;
|
||||
}
|
||||
|
||||
Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
BL::Object &b_ob,
|
||||
BL::Object &b_ob_instance,
|
||||
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);
|
||||
|
||||
/* Find shader indices. */
|
||||
array<Node *> used_shaders = find_used_shaders(b_ob);
|
||||
|
||||
/* Ensure we only sync instanced geometry once. */
|
||||
Geometry *geom = geometry_map.find(key);
|
||||
if (geom) {
|
||||
@@ -124,7 +131,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
|
||||
foreach (Node *node, geom->get_used_shaders()) {
|
||||
Shader *shader = static_cast<Shader *>(node);
|
||||
if (shader->need_update_geometry) {
|
||||
if (shader->need_update_geometry()) {
|
||||
attribute_recalc = true;
|
||||
}
|
||||
}
|
||||
|
@@ -285,12 +285,10 @@ static void attr_create_sculpt_vertex_color(Scene *scene,
|
||||
BL::Mesh &b_mesh,
|
||||
bool subdivision)
|
||||
{
|
||||
BL::Mesh::sculpt_vertex_colors_iterator l;
|
||||
|
||||
for (b_mesh.sculpt_vertex_colors.begin(l); l != b_mesh.sculpt_vertex_colors.end(); ++l) {
|
||||
const bool active_render = l->active_render();
|
||||
for (BL::MeshVertColorLayer &l : b_mesh.sculpt_vertex_colors) {
|
||||
const bool active_render = l.active_render();
|
||||
AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE;
|
||||
ustring vcol_name = ustring(l->name().c_str());
|
||||
ustring vcol_name = ustring(l.name().c_str());
|
||||
|
||||
const bool need_vcol = mesh->need_attribute(scene, vcol_name) ||
|
||||
mesh->need_attribute(scene, vcol_std);
|
||||
@@ -307,7 +305,7 @@ static void attr_create_sculpt_vertex_color(Scene *scene,
|
||||
int numverts = b_mesh.vertices.length();
|
||||
|
||||
for (int i = 0; i < numverts; i++) {
|
||||
*(cdata++) = get_float4(l->data[i].color());
|
||||
*(cdata++) = get_float4(l.data[i].color());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -315,12 +313,10 @@ static void attr_create_sculpt_vertex_color(Scene *scene,
|
||||
/* Create vertex color attributes. */
|
||||
static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision)
|
||||
{
|
||||
BL::Mesh::vertex_colors_iterator l;
|
||||
|
||||
for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) {
|
||||
const bool active_render = l->active_render();
|
||||
for (BL::MeshLoopColorLayer &l : b_mesh.vertex_colors) {
|
||||
const bool active_render = l.active_render();
|
||||
AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE;
|
||||
ustring vcol_name = ustring(l->name().c_str());
|
||||
ustring vcol_name = ustring(l.name().c_str());
|
||||
|
||||
const bool need_vcol = mesh->need_attribute(scene, vcol_name) ||
|
||||
mesh->need_attribute(scene, vcol_std);
|
||||
@@ -339,13 +335,12 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
|
||||
vcol_attr = mesh->subd_attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
|
||||
}
|
||||
|
||||
BL::Mesh::polygons_iterator p;
|
||||
uchar4 *cdata = vcol_attr->data_uchar4();
|
||||
|
||||
for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
|
||||
int n = p->loop_total();
|
||||
for (BL::MeshPolygon &p : b_mesh.polygons) {
|
||||
int n = p.loop_total();
|
||||
for (int i = 0; i < n; i++) {
|
||||
float4 color = get_float4(l->data[p->loop_start() + i].color());
|
||||
float4 color = get_float4(l.data[p.loop_start() + i].color());
|
||||
/* Compress/encode vertex color using the sRGB curve. */
|
||||
*(cdata++) = color_float4_to_uchar4(color);
|
||||
}
|
||||
@@ -359,14 +354,13 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
|
||||
vcol_attr = mesh->attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
|
||||
}
|
||||
|
||||
BL::Mesh::loop_triangles_iterator t;
|
||||
uchar4 *cdata = vcol_attr->data_uchar4();
|
||||
|
||||
for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) {
|
||||
int3 li = get_int3(t->loops());
|
||||
float4 c1 = get_float4(l->data[li[0]].color());
|
||||
float4 c2 = get_float4(l->data[li[1]].color());
|
||||
float4 c3 = get_float4(l->data[li[2]].color());
|
||||
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
|
||||
int3 li = get_int3(t.loops());
|
||||
float4 c1 = get_float4(l.data[li[0]].color());
|
||||
float4 c2 = get_float4(l.data[li[1]].color());
|
||||
float4 c3 = get_float4(l.data[li[2]].color());
|
||||
|
||||
/* Compress/encode vertex color using the sRGB curve. */
|
||||
cdata[0] = color_float4_to_uchar4(c1);
|
||||
@@ -383,14 +377,12 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
|
||||
static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
|
||||
{
|
||||
if (b_mesh.uv_layers.length() != 0) {
|
||||
BL::Mesh::uv_layers_iterator l;
|
||||
|
||||
for (b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l) {
|
||||
const bool active_render = l->active_render();
|
||||
for (BL::MeshUVLoopLayer &l : b_mesh.uv_layers) {
|
||||
const bool active_render = l.active_render();
|
||||
AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
|
||||
ustring uv_name = ustring(l->name().c_str());
|
||||
ustring uv_name = ustring(l.name().c_str());
|
||||
AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE;
|
||||
ustring tangent_name = ustring((string(l->name().c_str()) + ".tangent").c_str());
|
||||
ustring tangent_name = ustring((string(l.name().c_str()) + ".tangent").c_str());
|
||||
|
||||
/* Denotes whether UV map was requested directly. */
|
||||
const bool need_uv = mesh->need_attribute(scene, uv_name) ||
|
||||
@@ -412,14 +404,13 @@ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
|
||||
uv_attr = mesh->attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER);
|
||||
}
|
||||
|
||||
BL::Mesh::loop_triangles_iterator t;
|
||||
float2 *fdata = uv_attr->data_float2();
|
||||
|
||||
for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) {
|
||||
int3 li = get_int3(t->loops());
|
||||
fdata[0] = get_float2(l->data[li[0]].uv());
|
||||
fdata[1] = get_float2(l->data[li[1]].uv());
|
||||
fdata[2] = get_float2(l->data[li[2]].uv());
|
||||
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
|
||||
int3 li = get_int3(t.loops());
|
||||
fdata[0] = get_float2(l.data[li[0]].uv());
|
||||
fdata[1] = get_float2(l.data[li[1]].uv());
|
||||
fdata[2] = get_float2(l.data[li[2]].uv());
|
||||
fdata += 3;
|
||||
}
|
||||
}
|
||||
@@ -427,10 +418,10 @@ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
|
||||
/* UV tangent */
|
||||
if (need_tangent) {
|
||||
AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE;
|
||||
ustring sign_name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str());
|
||||
ustring sign_name = ustring((string(l.name().c_str()) + ".tangent_sign").c_str());
|
||||
bool need_sign = (mesh->need_attribute(scene, sign_name) ||
|
||||
mesh->need_attribute(scene, sign_std));
|
||||
mikk_compute_tangents(b_mesh, l->name().c_str(), mesh, need_sign, active_render);
|
||||
mikk_compute_tangents(b_mesh, l.name().c_str(), mesh, need_sign, active_render);
|
||||
}
|
||||
/* Remove temporarily created UV attribute. */
|
||||
if (!need_uv && uv_attr != NULL) {
|
||||
@@ -480,13 +471,12 @@ static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
|
||||
uv_attr->flags |= ATTR_SUBDIVIDED;
|
||||
}
|
||||
|
||||
BL::Mesh::polygons_iterator p;
|
||||
float2 *fdata = uv_attr->data_float2();
|
||||
|
||||
for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
|
||||
int n = p->loop_total();
|
||||
for (BL::MeshPolygon &p : b_mesh.polygons) {
|
||||
int n = p.loop_total();
|
||||
for (int j = 0; j < n; j++) {
|
||||
*(fdata++) = get_float2(l->data[p->loop_start() + j].uv());
|
||||
*(fdata++) = get_float2(l->data[p.loop_start() + j].uv());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -706,9 +696,8 @@ static void attr_create_random_per_island(Scene *scene,
|
||||
|
||||
DisjointSet vertices_sets(number_of_vertices);
|
||||
|
||||
BL::Mesh::edges_iterator e;
|
||||
for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
|
||||
vertices_sets.join(e->vertices()[0], e->vertices()[1]);
|
||||
for (BL::MeshEdge &e : b_mesh.edges) {
|
||||
vertices_sets.join(e.vertices()[0], e.vertices()[1]);
|
||||
}
|
||||
|
||||
AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
|
||||
@@ -716,15 +705,13 @@ static void attr_create_random_per_island(Scene *scene,
|
||||
float *data = attribute->data_float();
|
||||
|
||||
if (!subdivision) {
|
||||
BL::Mesh::loop_triangles_iterator t;
|
||||
for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) {
|
||||
data[t->index()] = hash_uint_to_float(vertices_sets.find(t->vertices()[0]));
|
||||
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
|
||||
data[t.index()] = hash_uint_to_float(vertices_sets.find(t.vertices()[0]));
|
||||
}
|
||||
}
|
||||
else {
|
||||
BL::Mesh::polygons_iterator p;
|
||||
for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
|
||||
data[p->index()] = hash_uint_to_float(vertices_sets.find(p->vertices()[0]));
|
||||
for (BL::MeshPolygon &p : b_mesh.polygons) {
|
||||
data[p.index()] = hash_uint_to_float(vertices_sets.find(p.vertices()[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -756,10 +743,9 @@ static void create_mesh(Scene *scene,
|
||||
numtris = numfaces;
|
||||
}
|
||||
else {
|
||||
BL::Mesh::polygons_iterator p;
|
||||
for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
|
||||
numngons += (p->loop_total() == 4) ? 0 : 1;
|
||||
numcorners += p->loop_total();
|
||||
for (BL::MeshPolygon &p : b_mesh.polygons) {
|
||||
numngons += (p.loop_total() == 4) ? 0 : 1;
|
||||
numcorners += p.loop_total();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -803,17 +789,15 @@ static void create_mesh(Scene *scene,
|
||||
|
||||
/* create faces */
|
||||
if (!subdivision) {
|
||||
BL::Mesh::loop_triangles_iterator t;
|
||||
|
||||
for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) {
|
||||
BL::MeshPolygon p = b_mesh.polygons[t->polygon_index()];
|
||||
int3 vi = get_int3(t->vertices());
|
||||
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
|
||||
BL::MeshPolygon p = b_mesh.polygons[t.polygon_index()];
|
||||
int3 vi = get_int3(t.vertices());
|
||||
|
||||
int shader = clamp(p.material_index(), 0, used_shaders.size() - 1);
|
||||
bool smooth = p.use_smooth() || use_loop_normals;
|
||||
|
||||
if (use_loop_normals) {
|
||||
BL::Array<float, 9> loop_normals = t->split_normals();
|
||||
BL::Array<float, 9> loop_normals = t.split_normals();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
N[vi[i]] = make_float3(
|
||||
loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]);
|
||||
@@ -828,18 +812,17 @@ static void create_mesh(Scene *scene,
|
||||
}
|
||||
}
|
||||
else {
|
||||
BL::Mesh::polygons_iterator p;
|
||||
vector<int> vi;
|
||||
|
||||
for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
|
||||
int n = p->loop_total();
|
||||
int shader = clamp(p->material_index(), 0, used_shaders.size() - 1);
|
||||
bool smooth = p->use_smooth() || use_loop_normals;
|
||||
for (BL::MeshPolygon &p : b_mesh.polygons) {
|
||||
int n = p.loop_total();
|
||||
int shader = clamp(p.material_index(), 0, used_shaders.size() - 1);
|
||||
bool smooth = p.use_smooth() || use_loop_normals;
|
||||
|
||||
vi.resize(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
/* NOTE: Autosmooth is already taken care about. */
|
||||
vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index();
|
||||
vi[i] = b_mesh.loops[p.loop_start() + i].vertex_index();
|
||||
}
|
||||
|
||||
/* create subd faces */
|
||||
@@ -891,19 +874,18 @@ static void create_subd_mesh(Scene *scene,
|
||||
|
||||
/* export creases */
|
||||
size_t num_creases = 0;
|
||||
BL::Mesh::edges_iterator e;
|
||||
|
||||
for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
|
||||
if (e->crease() != 0.0f) {
|
||||
for (BL::MeshEdge &e : b_mesh.edges) {
|
||||
if (e.crease() != 0.0f) {
|
||||
num_creases++;
|
||||
}
|
||||
}
|
||||
|
||||
mesh->reserve_subd_creases(num_creases);
|
||||
|
||||
for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
|
||||
if (e->crease() != 0.0f) {
|
||||
mesh->add_crease(e->vertices()[0], e->vertices()[1], e->crease());
|
||||
for (BL::MeshEdge &e : b_mesh.edges) {
|
||||
if (e.crease() != 0.0f) {
|
||||
mesh->add_crease(e.vertices()[0], e.vertices()[1], e.crease());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1075,15 +1057,8 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *me
|
||||
mesh->set_value(socket, new_mesh, socket);
|
||||
}
|
||||
|
||||
mesh->attributes.clear();
|
||||
foreach (Attribute &attr, new_mesh.attributes.attributes) {
|
||||
mesh->attributes.attributes.push_back(std::move(attr));
|
||||
}
|
||||
|
||||
mesh->subd_attributes.clear();
|
||||
foreach (Attribute &attr, new_mesh.subd_attributes.attributes) {
|
||||
mesh->subd_attributes.attributes.push_back(std::move(attr));
|
||||
}
|
||||
mesh->attributes.update(std::move(new_mesh.attributes));
|
||||
mesh->subd_attributes.update(std::move(new_mesh.subd_attributes));
|
||||
|
||||
mesh->set_num_subd_faces(new_mesh.get_num_subd_faces());
|
||||
|
||||
|
@@ -51,10 +51,11 @@ bool BlenderSync::BKE_object_is_modified(BL::Object &b_ob)
|
||||
}
|
||||
else {
|
||||
/* object level material links */
|
||||
BL::Object::material_slots_iterator slot;
|
||||
for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot)
|
||||
if (slot->link() == BL::MaterialSlot::link_OBJECT)
|
||||
for (BL::MaterialSlot &b_slot : b_ob.material_slots) {
|
||||
if (b_slot.link() == BL::MaterialSlot::link_OBJECT) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -243,9 +244,6 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
|
||||
/* holdout */
|
||||
object->set_use_holdout(use_holdout);
|
||||
if (object->use_holdout_is_modified()) {
|
||||
scene->object_manager->tag_update(scene);
|
||||
}
|
||||
|
||||
object->set_visibility(visibility);
|
||||
|
||||
|
@@ -57,7 +57,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
|
||||
|
||||
/* no update needed? */
|
||||
if (!need_update && !object->get_geometry()->is_modified() &&
|
||||
!scene->object_manager->need_update)
|
||||
!scene->object_manager->need_update())
|
||||
return true;
|
||||
|
||||
/* first time used in this sync loop? clear and tag update */
|
||||
@@ -85,7 +85,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
|
||||
object->set_particle_index(psys->particles.size() - 1);
|
||||
|
||||
if (object->particle_index_is_modified())
|
||||
scene->object_manager->tag_update(scene);
|
||||
scene->object_manager->tag_update(scene, ObjectManager::PARTICLE_MODIFIED);
|
||||
|
||||
/* return that this object has particle data */
|
||||
return true;
|
||||
|
@@ -597,22 +597,19 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
|
||||
bool removed;
|
||||
|
||||
do {
|
||||
BL::Node::inputs_iterator b_input;
|
||||
BL::Node::outputs_iterator b_output;
|
||||
|
||||
removed = false;
|
||||
|
||||
for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
|
||||
if (used_sockets.find(b_input->ptr.data) == used_sockets.end()) {
|
||||
b_node.inputs.remove(b_data, *b_input);
|
||||
for (BL::NodeSocket &b_input : b_node.inputs) {
|
||||
if (used_sockets.find(b_input.ptr.data) == used_sockets.end()) {
|
||||
b_node.inputs.remove(b_data, b_input);
|
||||
removed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
|
||||
if (used_sockets.find(b_output->ptr.data) == used_sockets.end()) {
|
||||
b_node.outputs.remove(b_data, *b_output);
|
||||
for (BL::NodeSocket &b_output : b_node.outputs) {
|
||||
if (used_sockets.find(b_output.ptr.data) == used_sockets.end()) {
|
||||
b_node.outputs.remove(b_data, b_output);
|
||||
removed = true;
|
||||
break;
|
||||
}
|
||||
|
@@ -358,11 +358,7 @@ void BlenderSession::do_write_update_render_tile(RenderTile &rtile,
|
||||
|
||||
if (do_read_only) {
|
||||
/* copy each pass */
|
||||
BL::RenderLayer::passes_iterator b_iter;
|
||||
|
||||
for (b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
|
||||
BL::RenderPass b_pass(*b_iter);
|
||||
|
||||
for (BL::RenderPass &b_pass : b_rlay.passes) {
|
||||
/* find matching pass type */
|
||||
PassType pass_type = BlenderSync::get_pass_type(b_pass);
|
||||
int components = b_pass.channels();
|
||||
@@ -552,7 +548,6 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
|
||||
int seed = scene->integrator->get_seed();
|
||||
seed += hash_uint2(seed, hash_uint2(view_index * 0xdeadbeef, 0));
|
||||
scene->integrator->set_seed(seed);
|
||||
scene->integrator->tag_update(scene);
|
||||
}
|
||||
|
||||
/* Update number of samples per layer. */
|
||||
@@ -736,10 +731,7 @@ void BlenderSession::do_write_update_render_result(BL::RenderLayer &b_rlay,
|
||||
|
||||
if (!do_update_only) {
|
||||
/* copy each pass */
|
||||
BL::RenderLayer::passes_iterator b_iter;
|
||||
|
||||
for (b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
|
||||
BL::RenderPass b_pass(*b_iter);
|
||||
for (BL::RenderPass &b_pass : b_rlay.passes) {
|
||||
int components = b_pass.channels();
|
||||
|
||||
/* Copy pixels from regular render passes. */
|
||||
@@ -1116,10 +1108,6 @@ void BlenderSession::update_resumable_tile_manager(int num_samples)
|
||||
|
||||
scene->integrator->set_start_sample(rounded_range_start_sample);
|
||||
|
||||
if (scene->integrator->is_modified()) {
|
||||
scene->integrator->tag_update(scene);
|
||||
}
|
||||
|
||||
session->tile_manager.range_start_sample = rounded_range_start_sample;
|
||||
session->tile_manager.range_num_samples = rounded_range_num_samples;
|
||||
}
|
||||
|
@@ -148,15 +148,13 @@ BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_r
|
||||
|
||||
static BL::NodeSocket get_node_output(BL::Node &b_node, const string &name)
|
||||
{
|
||||
BL::Node::outputs_iterator b_out;
|
||||
|
||||
for (b_node.outputs.begin(b_out); b_out != b_node.outputs.end(); ++b_out)
|
||||
if (b_out->name() == name)
|
||||
return *b_out;
|
||||
|
||||
for (BL::NodeSocket &b_out : b_node.outputs) {
|
||||
if (b_out.name() == name) {
|
||||
return b_out;
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
|
||||
return *b_out;
|
||||
return *b_node.outputs.begin();
|
||||
}
|
||||
|
||||
static float3 get_node_output_rgba(BL::Node &b_node, const string &name)
|
||||
@@ -723,9 +721,8 @@ static ShaderNode *add_node(Scene *scene,
|
||||
image->set_alpha_type(get_image_alpha_type(b_image));
|
||||
|
||||
array<int> tiles;
|
||||
BL::Image::tiles_iterator b_iter;
|
||||
for (b_image.tiles.begin(b_iter); b_iter != b_image.tiles.end(); ++b_iter) {
|
||||
tiles.push_back_slow(b_iter->number());
|
||||
for (BL::UDIMTile &b_tile : b_image.tiles) {
|
||||
tiles.push_back_slow(b_tile.number());
|
||||
}
|
||||
image->set_tiles(tiles);
|
||||
|
||||
@@ -1012,18 +1009,18 @@ static ShaderInput *node_find_input_by_name(ShaderNode *node,
|
||||
string name = b_socket.name();
|
||||
|
||||
if (node_use_modified_socket_name(node)) {
|
||||
BL::Node::inputs_iterator b_input;
|
||||
bool found = false;
|
||||
int counter = 0, total = 0;
|
||||
|
||||
for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
|
||||
if (b_input->name() == name) {
|
||||
if (!found)
|
||||
for (BL::NodeSocket &b_input : b_node.inputs) {
|
||||
if (b_input.name() == name) {
|
||||
if (!found) {
|
||||
counter++;
|
||||
}
|
||||
total++;
|
||||
}
|
||||
|
||||
if (b_input->ptr.data == b_socket.ptr.data)
|
||||
if (b_input.ptr.data == b_socket.ptr.data)
|
||||
found = true;
|
||||
}
|
||||
|
||||
@@ -1045,19 +1042,20 @@ static ShaderOutput *node_find_output_by_name(ShaderNode *node,
|
||||
string name = b_socket.name();
|
||||
|
||||
if (node_use_modified_socket_name(node)) {
|
||||
BL::Node::outputs_iterator b_output;
|
||||
bool found = false;
|
||||
int counter = 0, total = 0;
|
||||
|
||||
for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
|
||||
if (b_output->name() == name) {
|
||||
if (!found)
|
||||
for (BL::NodeSocket &b_output : b_node.outputs) {
|
||||
if (b_output.name() == name) {
|
||||
if (!found) {
|
||||
counter++;
|
||||
}
|
||||
total++;
|
||||
}
|
||||
|
||||
if (b_output->ptr.data == b_socket.ptr.data)
|
||||
if (b_output.ptr.data == b_socket.ptr.data) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* rename if needed */
|
||||
@@ -1082,25 +1080,19 @@ static void add_nodes(Scene *scene,
|
||||
const ProxyMap &proxy_output_map)
|
||||
{
|
||||
/* add nodes */
|
||||
BL::ShaderNodeTree::nodes_iterator b_node;
|
||||
PtrInputMap input_map;
|
||||
PtrOutputMap output_map;
|
||||
|
||||
BL::Node::inputs_iterator b_input;
|
||||
BL::Node::outputs_iterator b_output;
|
||||
|
||||
/* find the node to use for output if there are multiple */
|
||||
BL::ShaderNode output_node = b_ntree.get_output_node(
|
||||
BL::ShaderNodeOutputMaterial::target_CYCLES);
|
||||
|
||||
/* add nodes */
|
||||
for (b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
|
||||
if (b_node->mute() || b_node->is_a(&RNA_NodeReroute)) {
|
||||
for (BL::Node &b_node : b_ntree.nodes) {
|
||||
if (b_node.mute() || b_node.is_a(&RNA_NodeReroute)) {
|
||||
/* replace muted node with internal links */
|
||||
BL::Node::internal_links_iterator b_link;
|
||||
for (b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end();
|
||||
++b_link) {
|
||||
BL::NodeSocket to_socket(b_link->to_socket());
|
||||
for (BL::NodeLink &b_link : b_node.internal_links) {
|
||||
BL::NodeSocket to_socket(b_link.to_socket());
|
||||
SocketType::Type to_socket_type = convert_socket_type(to_socket);
|
||||
if (to_socket_type == SocketType::UNDEFINED) {
|
||||
continue;
|
||||
@@ -1108,22 +1100,22 @@ static void add_nodes(Scene *scene,
|
||||
|
||||
ConvertNode *proxy = graph->create_node<ConvertNode>(to_socket_type, to_socket_type, true);
|
||||
|
||||
input_map[b_link->from_socket().ptr.data] = proxy->inputs[0];
|
||||
output_map[b_link->to_socket().ptr.data] = proxy->outputs[0];
|
||||
input_map[b_link.from_socket().ptr.data] = proxy->inputs[0];
|
||||
output_map[b_link.to_socket().ptr.data] = proxy->outputs[0];
|
||||
|
||||
graph->add(proxy);
|
||||
}
|
||||
}
|
||||
else if (b_node->is_a(&RNA_ShaderNodeGroup) || b_node->is_a(&RNA_NodeCustomGroup) ||
|
||||
b_node->is_a(&RNA_ShaderNodeCustomGroup)) {
|
||||
else if (b_node.is_a(&RNA_ShaderNodeGroup) || b_node.is_a(&RNA_NodeCustomGroup) ||
|
||||
b_node.is_a(&RNA_ShaderNodeCustomGroup)) {
|
||||
|
||||
BL::ShaderNodeTree b_group_ntree(PointerRNA_NULL);
|
||||
if (b_node->is_a(&RNA_ShaderNodeGroup))
|
||||
b_group_ntree = BL::ShaderNodeTree(((BL::NodeGroup)(*b_node)).node_tree());
|
||||
else if (b_node->is_a(&RNA_NodeCustomGroup))
|
||||
b_group_ntree = BL::ShaderNodeTree(((BL::NodeCustomGroup)(*b_node)).node_tree());
|
||||
if (b_node.is_a(&RNA_ShaderNodeGroup))
|
||||
b_group_ntree = BL::ShaderNodeTree(((BL::NodeGroup)(b_node)).node_tree());
|
||||
else if (b_node.is_a(&RNA_NodeCustomGroup))
|
||||
b_group_ntree = BL::ShaderNodeTree(((BL::NodeCustomGroup)(b_node)).node_tree());
|
||||
else
|
||||
b_group_ntree = BL::ShaderNodeTree(((BL::ShaderNodeCustomGroup)(*b_node)).node_tree());
|
||||
b_group_ntree = BL::ShaderNodeTree(((BL::ShaderNodeCustomGroup)(b_node)).node_tree());
|
||||
|
||||
ProxyMap group_proxy_input_map, group_proxy_output_map;
|
||||
|
||||
@@ -1131,8 +1123,8 @@ static void add_nodes(Scene *scene,
|
||||
* Do this even if the node group has no internal tree,
|
||||
* so that links have something to connect to and assert won't fail.
|
||||
*/
|
||||
for (b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
|
||||
SocketType::Type input_type = convert_socket_type(*b_input);
|
||||
for (BL::NodeSocket &b_input : b_node.inputs) {
|
||||
SocketType::Type input_type = convert_socket_type(b_input);
|
||||
if (input_type == SocketType::UNDEFINED) {
|
||||
continue;
|
||||
}
|
||||
@@ -1141,14 +1133,14 @@ static void add_nodes(Scene *scene,
|
||||
graph->add(proxy);
|
||||
|
||||
/* register the proxy node for internal binding */
|
||||
group_proxy_input_map[b_input->identifier()] = proxy;
|
||||
group_proxy_input_map[b_input.identifier()] = proxy;
|
||||
|
||||
input_map[b_input->ptr.data] = proxy->inputs[0];
|
||||
input_map[b_input.ptr.data] = proxy->inputs[0];
|
||||
|
||||
set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree);
|
||||
set_default_value(proxy->inputs[0], b_input, b_data, b_ntree);
|
||||
}
|
||||
for (b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
|
||||
SocketType::Type output_type = convert_socket_type(*b_output);
|
||||
for (BL::NodeSocket &b_output : b_node.outputs) {
|
||||
SocketType::Type output_type = convert_socket_type(b_output);
|
||||
if (output_type == SocketType::UNDEFINED) {
|
||||
continue;
|
||||
}
|
||||
@@ -1157,9 +1149,9 @@ static void add_nodes(Scene *scene,
|
||||
graph->add(proxy);
|
||||
|
||||
/* register the proxy node for internal binding */
|
||||
group_proxy_output_map[b_output->identifier()] = proxy;
|
||||
group_proxy_output_map[b_output.identifier()] = proxy;
|
||||
|
||||
output_map[b_output->ptr.data] = proxy->outputs[0];
|
||||
output_map[b_output.ptr.data] = proxy->outputs[0];
|
||||
}
|
||||
|
||||
if (b_group_ntree) {
|
||||
@@ -1174,30 +1166,30 @@ static void add_nodes(Scene *scene,
|
||||
group_proxy_output_map);
|
||||
}
|
||||
}
|
||||
else if (b_node->is_a(&RNA_NodeGroupInput)) {
|
||||
else if (b_node.is_a(&RNA_NodeGroupInput)) {
|
||||
/* map each socket to a proxy node */
|
||||
for (b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
|
||||
ProxyMap::const_iterator proxy_it = proxy_input_map.find(b_output->identifier());
|
||||
for (BL::NodeSocket &b_output : b_node.outputs) {
|
||||
ProxyMap::const_iterator proxy_it = proxy_input_map.find(b_output.identifier());
|
||||
if (proxy_it != proxy_input_map.end()) {
|
||||
ConvertNode *proxy = proxy_it->second;
|
||||
|
||||
output_map[b_output->ptr.data] = proxy->outputs[0];
|
||||
output_map[b_output.ptr.data] = proxy->outputs[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (b_node->is_a(&RNA_NodeGroupOutput)) {
|
||||
BL::NodeGroupOutput b_output_node(*b_node);
|
||||
else if (b_node.is_a(&RNA_NodeGroupOutput)) {
|
||||
BL::NodeGroupOutput b_output_node(b_node);
|
||||
/* only the active group output is used */
|
||||
if (b_output_node.is_active_output()) {
|
||||
/* map each socket to a proxy node */
|
||||
for (b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
|
||||
ProxyMap::const_iterator proxy_it = proxy_output_map.find(b_input->identifier());
|
||||
for (BL::NodeSocket &b_input : b_node.inputs) {
|
||||
ProxyMap::const_iterator proxy_it = proxy_output_map.find(b_input.identifier());
|
||||
if (proxy_it != proxy_output_map.end()) {
|
||||
ConvertNode *proxy = proxy_it->second;
|
||||
|
||||
input_map[b_input->ptr.data] = proxy->inputs[0];
|
||||
input_map[b_input.ptr.data] = proxy->inputs[0];
|
||||
|
||||
set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree);
|
||||
set_default_value(proxy->inputs[0], b_input, b_data, b_ntree);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1205,52 +1197,49 @@ static void add_nodes(Scene *scene,
|
||||
else {
|
||||
ShaderNode *node = NULL;
|
||||
|
||||
if (b_node->ptr.data == output_node.ptr.data) {
|
||||
if (b_node.ptr.data == output_node.ptr.data) {
|
||||
node = graph->output();
|
||||
}
|
||||
else {
|
||||
BL::ShaderNode b_shader_node(*b_node);
|
||||
BL::ShaderNode b_shader_node(b_node);
|
||||
node = add_node(
|
||||
scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree, b_shader_node);
|
||||
}
|
||||
|
||||
if (node) {
|
||||
/* map node sockets for linking */
|
||||
for (b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
|
||||
ShaderInput *input = node_find_input_by_name(node, *b_node, *b_input);
|
||||
for (BL::NodeSocket &b_input : b_node.inputs) {
|
||||
ShaderInput *input = node_find_input_by_name(node, b_node, b_input);
|
||||
if (!input) {
|
||||
/* XXX should not happen, report error? */
|
||||
continue;
|
||||
}
|
||||
input_map[b_input->ptr.data] = input;
|
||||
input_map[b_input.ptr.data] = input;
|
||||
|
||||
set_default_value(input, *b_input, b_data, b_ntree);
|
||||
set_default_value(input, b_input, b_data, b_ntree);
|
||||
}
|
||||
for (b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
|
||||
ShaderOutput *output = node_find_output_by_name(node, *b_node, *b_output);
|
||||
for (BL::NodeSocket &b_output : b_node.outputs) {
|
||||
ShaderOutput *output = node_find_output_by_name(node, b_node, b_output);
|
||||
if (!output) {
|
||||
/* XXX should not happen, report error? */
|
||||
continue;
|
||||
}
|
||||
output_map[b_output->ptr.data] = output;
|
||||
output_map[b_output.ptr.data] = output;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* connect nodes */
|
||||
BL::NodeTree::links_iterator b_link;
|
||||
|
||||
for (b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) {
|
||||
for (BL::NodeLink &b_link : b_ntree.links) {
|
||||
/* Ignore invalid links to avoid unwanted cycles created in graph.
|
||||
* Also ignore links with unavailable sockets. */
|
||||
if (!(b_link->is_valid() && b_link->from_socket().enabled() &&
|
||||
b_link->to_socket().enabled())) {
|
||||
if (!(b_link.is_valid() && b_link.from_socket().enabled() && b_link.to_socket().enabled())) {
|
||||
continue;
|
||||
}
|
||||
/* get blender link data */
|
||||
BL::NodeSocket b_from_sock = b_link->from_socket();
|
||||
BL::NodeSocket b_to_sock = b_link->to_socket();
|
||||
BL::NodeSocket b_from_sock = b_link.from_socket();
|
||||
BL::NodeSocket b_to_sock = b_link.to_socket();
|
||||
|
||||
ShaderOutput *output = 0;
|
||||
ShaderInput *input = 0;
|
||||
@@ -1298,13 +1287,12 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
|
||||
TaskPool pool;
|
||||
set<Shader *> updated_shaders;
|
||||
|
||||
BL::Depsgraph::ids_iterator b_id;
|
||||
for (b_depsgraph.ids.begin(b_id); b_id != b_depsgraph.ids.end(); ++b_id) {
|
||||
if (!b_id->is_a(&RNA_Material)) {
|
||||
for (BL::ID &b_id : b_depsgraph.ids) {
|
||||
if (!b_id.is_a(&RNA_Material)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BL::Material b_mat(*b_id);
|
||||
BL::Material b_mat(b_id);
|
||||
Shader *shader;
|
||||
|
||||
/* test if we need to sync */
|
||||
@@ -1497,7 +1485,6 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
|
||||
|
||||
shader->set_graph(graph);
|
||||
shader->tag_update(scene);
|
||||
background->tag_update(scene);
|
||||
}
|
||||
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
@@ -1517,8 +1504,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
|
||||
viewport_parameters.custom_viewport_parameters());
|
||||
background->set_use_ao(background->get_use_ao() && view_layer.use_background_ao);
|
||||
|
||||
if (background->is_modified())
|
||||
background->tag_update(scene);
|
||||
background->tag_update(scene);
|
||||
}
|
||||
|
||||
/* Sync Lights */
|
||||
@@ -1527,13 +1513,12 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
|
||||
{
|
||||
shader_map.set_default(scene->default_light);
|
||||
|
||||
BL::Depsgraph::ids_iterator b_id;
|
||||
for (b_depsgraph.ids.begin(b_id); b_id != b_depsgraph.ids.end(); ++b_id) {
|
||||
if (!b_id->is_a(&RNA_Light)) {
|
||||
for (BL::ID &b_id : b_depsgraph.ids) {
|
||||
if (!b_id.is_a(&RNA_Light)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BL::Light b_light(*b_id);
|
||||
BL::Light b_light(b_id);
|
||||
Shader *shader;
|
||||
|
||||
/* test if we need to sync */
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "render/mesh.h"
|
||||
#include "render/nodes.h"
|
||||
#include "render/object.h"
|
||||
#include "render/procedural.h"
|
||||
#include "render/scene.h"
|
||||
#include "render/shader.h"
|
||||
|
||||
@@ -131,9 +132,8 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
|
||||
}
|
||||
|
||||
/* Iterate over all IDs in this depsgraph. */
|
||||
BL::Depsgraph::updates_iterator b_update;
|
||||
for (b_depsgraph.updates.begin(b_update); b_update != b_depsgraph.updates.end(); ++b_update) {
|
||||
BL::ID b_id(b_update->id());
|
||||
for (BL::DepsgraphUpdate &b_update : b_depsgraph.updates) {
|
||||
BL::ID b_id(b_update.id());
|
||||
|
||||
/* Material */
|
||||
if (b_id.is_a(&RNA_Material)) {
|
||||
@@ -151,17 +151,17 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
|
||||
const bool is_geometry = object_is_geometry(b_ob);
|
||||
const bool is_light = !is_geometry && object_is_light(b_ob);
|
||||
|
||||
if (b_ob.is_instancer() && b_update->is_updated_shading()) {
|
||||
if (b_ob.is_instancer() && b_update.is_updated_shading()) {
|
||||
/* Needed for e.g. object color updates on instancer. */
|
||||
object_map.set_recalc(b_ob);
|
||||
}
|
||||
|
||||
if (is_geometry || is_light) {
|
||||
const bool updated_geometry = b_update->is_updated_geometry();
|
||||
const bool updated_geometry = b_update.is_updated_geometry();
|
||||
|
||||
/* Geometry (mesh, hair, volume). */
|
||||
if (is_geometry) {
|
||||
if (b_update->is_updated_transform() || b_update->is_updated_shading()) {
|
||||
if (b_update.is_updated_transform() || b_update.is_updated_shading()) {
|
||||
object_map.set_recalc(b_ob);
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
|
||||
}
|
||||
/* Light */
|
||||
else if (is_light) {
|
||||
if (b_update->is_updated_transform() || b_update->is_updated_shading()) {
|
||||
if (b_update.is_updated_transform() || b_update.is_updated_shading()) {
|
||||
object_map.set_recalc(b_ob);
|
||||
light_map.set_recalc(b_ob);
|
||||
}
|
||||
@@ -302,11 +302,6 @@ void BlenderSync::sync_integrator()
|
||||
integrator->set_sample_clamp_direct(get_float(cscene, "sample_clamp_direct"));
|
||||
integrator->set_sample_clamp_indirect(get_float(cscene, "sample_clamp_indirect"));
|
||||
if (!preview) {
|
||||
if (integrator->get_motion_blur() != r.use_motion_blur()) {
|
||||
scene->object_manager->tag_update(scene);
|
||||
scene->camera->tag_modified();
|
||||
}
|
||||
|
||||
integrator->set_motion_blur(r.use_motion_blur());
|
||||
}
|
||||
|
||||
@@ -375,8 +370,8 @@ void BlenderSync::sync_integrator()
|
||||
integrator->set_ao_bounces(0);
|
||||
}
|
||||
|
||||
if (integrator->is_modified())
|
||||
integrator->tag_update(scene);
|
||||
/* UPDATE_NONE as we don't want to tag the integrator as modified, just tag dependent things */
|
||||
integrator->tag_update(scene, Integrator::UPDATE_NONE);
|
||||
}
|
||||
|
||||
/* Film */
|
||||
@@ -471,16 +466,15 @@ void BlenderSync::sync_images()
|
||||
return;
|
||||
}
|
||||
/* Free buffers used by images which are not needed for render. */
|
||||
BL::BlendData::images_iterator b_image;
|
||||
for (b_data.images.begin(b_image); b_image != b_data.images.end(); ++b_image) {
|
||||
for (BL::Image &b_image : b_data.images) {
|
||||
/* TODO(sergey): Consider making it an utility function to check
|
||||
* whether image is considered builtin.
|
||||
*/
|
||||
const bool is_builtin = b_image->packed_file() ||
|
||||
b_image->source() == BL::Image::source_GENERATED ||
|
||||
b_image->source() == BL::Image::source_MOVIE || b_engine.is_preview();
|
||||
const bool is_builtin = b_image.packed_file() ||
|
||||
b_image.source() == BL::Image::source_GENERATED ||
|
||||
b_image.source() == BL::Image::source_MOVIE || b_engine.is_preview();
|
||||
if (is_builtin == false) {
|
||||
b_image->buffers_free();
|
||||
b_image.buffers_free();
|
||||
}
|
||||
/* TODO(sergey): Free builtin images not used by any shader. */
|
||||
}
|
||||
@@ -581,10 +575,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
|
||||
vector<Pass> passes;
|
||||
|
||||
/* loop over passes */
|
||||
BL::RenderLayer::passes_iterator b_pass_iter;
|
||||
|
||||
for (b_rlay.passes.begin(b_pass_iter); b_pass_iter != b_rlay.passes.end(); ++b_pass_iter) {
|
||||
BL::RenderPass b_pass(*b_pass_iter);
|
||||
for (BL::RenderPass &b_pass : b_rlay.passes) {
|
||||
PassType pass_type = get_pass_type(b_pass);
|
||||
|
||||
if (pass_type == PASS_MOTION && scene->integrator->get_motion_blur())
|
||||
@@ -729,7 +720,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
|
||||
|
||||
scene->film->set_pass_alpha_threshold(b_view_layer.pass_alpha_threshold());
|
||||
scene->film->tag_passes_update(scene, passes);
|
||||
scene->integrator->tag_update(scene);
|
||||
scene->integrator->tag_update(scene, Integrator::UPDATE_ALL);
|
||||
|
||||
return passes;
|
||||
}
|
||||
@@ -752,9 +743,8 @@ void BlenderSync::free_data_after_sync(BL::Depsgraph &b_depsgraph)
|
||||
/* TODO(sergey): We can actually remove the whole dependency graph,
|
||||
* but that will need some API support first.
|
||||
*/
|
||||
BL::Depsgraph::objects_iterator b_ob;
|
||||
for (b_depsgraph.objects.begin(b_ob); b_ob != b_depsgraph.objects.end(); ++b_ob) {
|
||||
b_ob->cache_release();
|
||||
for (BL::Object &b_ob : b_depsgraph.objects) {
|
||||
b_ob.cache_release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -853,7 +843,7 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
|
||||
preview_samples = preview_samples * preview_samples;
|
||||
}
|
||||
|
||||
if (get_enum(cscene, "progressive") == 0 && (params.device.type != DEVICE_OPTIX)) {
|
||||
if (get_enum(cscene, "progressive") == 0 && params.device.has_branched_path) {
|
||||
if (background) {
|
||||
params.samples = aa_samples;
|
||||
}
|
||||
|
@@ -134,6 +134,7 @@ class BlenderSync {
|
||||
void sync_view();
|
||||
|
||||
/* Shader */
|
||||
array<Node *> find_used_shaders(BL::Object &b_ob);
|
||||
void sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all);
|
||||
void sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d);
|
||||
void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree);
|
||||
|
@@ -538,11 +538,9 @@ static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_
|
||||
|
||||
static inline BL::FluidDomainSettings object_fluid_liquid_domain_find(BL::Object &b_ob)
|
||||
{
|
||||
BL::Object::modifiers_iterator b_mod;
|
||||
|
||||
for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
|
||||
if (b_mod->is_a(&RNA_FluidModifier)) {
|
||||
BL::FluidModifier b_mmd(*b_mod);
|
||||
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) {
|
||||
@@ -556,11 +554,9 @@ static inline BL::FluidDomainSettings object_fluid_liquid_domain_find(BL::Object
|
||||
|
||||
static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
|
||||
{
|
||||
BL::Object::modifiers_iterator b_mod;
|
||||
|
||||
for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
|
||||
if (b_mod->is_a(&RNA_FluidModifier)) {
|
||||
BL::FluidModifier b_mmd(*b_mod);
|
||||
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_GAS) {
|
||||
|
@@ -222,9 +222,7 @@ class BlenderVolumeLoader : public VDBImageLoader {
|
||||
b_volume.grids.load(b_data.ptr.data);
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
BL::Volume::grids_iterator b_grid_iter;
|
||||
for (b_volume.grids.begin(b_grid_iter); b_grid_iter != b_volume.grids.end(); ++b_grid_iter) {
|
||||
BL::VolumeGrid b_volume_grid(*b_grid_iter);
|
||||
for (BL::VolumeGrid &b_volume_grid : b_volume.grids) {
|
||||
if (b_volume_grid.name() == grid_name) {
|
||||
const bool unload = !b_volume_grid.is_loaded();
|
||||
|
||||
@@ -260,9 +258,7 @@ static void sync_volume_object(BL::BlendData &b_data,
|
||||
volume->set_object_space((b_render.space() == BL::VolumeRender::space_OBJECT));
|
||||
|
||||
/* Find grid with matching name. */
|
||||
BL::Volume::grids_iterator b_grid_iter;
|
||||
for (b_volume.grids.begin(b_grid_iter); b_grid_iter != b_volume.grids.end(); ++b_grid_iter) {
|
||||
BL::VolumeGrid b_grid = *b_grid_iter;
|
||||
for (BL::VolumeGrid &b_grid : b_volume.grids) {
|
||||
ustring name = ustring(b_grid.name());
|
||||
AttributeStandard std = ATTR_STD_NONE;
|
||||
|
||||
|
@@ -1929,18 +1929,19 @@ void CUDADevice::render(DeviceTask &task, RenderTile &rtile, device_vector<WorkT
|
||||
}
|
||||
|
||||
uint step_samples = divide_up(min_blocks * num_threads_per_block, wtile->w * wtile->h);
|
||||
if (task.adaptive_sampling.use) {
|
||||
step_samples = task.adaptive_sampling.align_static_samples(step_samples);
|
||||
}
|
||||
|
||||
/* Render all samples. */
|
||||
int start_sample = rtile.start_sample;
|
||||
int end_sample = rtile.start_sample + rtile.num_samples;
|
||||
|
||||
for (int sample = start_sample; sample < end_sample; sample += step_samples) {
|
||||
for (int sample = start_sample; sample < end_sample;) {
|
||||
/* Setup and copy work tile to device. */
|
||||
wtile->start_sample = sample;
|
||||
wtile->num_samples = min(step_samples, end_sample - sample);
|
||||
wtile->num_samples = step_samples;
|
||||
if (task.adaptive_sampling.use) {
|
||||
wtile->num_samples = task.adaptive_sampling.align_samples(sample, step_samples);
|
||||
}
|
||||
wtile->num_samples = min(wtile->num_samples, end_sample - sample);
|
||||
work_tiles.copy_to_device();
|
||||
|
||||
CUdeviceptr d_work_tiles = (CUdeviceptr)work_tiles.device_pointer;
|
||||
@@ -1962,7 +1963,8 @@ void CUDADevice::render(DeviceTask &task, RenderTile &rtile, device_vector<WorkT
|
||||
cuda_assert(cuCtxSynchronize());
|
||||
|
||||
/* Update progress. */
|
||||
rtile.sample = sample + wtile->num_samples;
|
||||
sample += wtile->num_samples;
|
||||
rtile.sample = sample;
|
||||
task.update_progress(&rtile, rtile.w * rtile.h * wtile->num_samples);
|
||||
|
||||
if (task.get_cancel()) {
|
||||
|
@@ -620,6 +620,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
|
||||
|
||||
info.has_half_images = true;
|
||||
info.has_volume_decoupled = true;
|
||||
info.has_branched_path = true;
|
||||
info.has_adaptive_stop_per_sample = true;
|
||||
info.has_osl = true;
|
||||
info.has_profiling = true;
|
||||
@@ -665,6 +666,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
|
||||
/* Accumulate device info. */
|
||||
info.has_half_images &= device.has_half_images;
|
||||
info.has_volume_decoupled &= device.has_volume_decoupled;
|
||||
info.has_branched_path &= device.has_branched_path;
|
||||
info.has_adaptive_stop_per_sample &= device.has_adaptive_stop_per_sample;
|
||||
info.has_osl &= device.has_osl;
|
||||
info.has_profiling &= device.has_profiling;
|
||||
|
@@ -79,6 +79,7 @@ class DeviceInfo {
|
||||
bool display_device; /* GPU is used as a display device. */
|
||||
bool has_half_images; /* Support half-float textures. */
|
||||
bool has_volume_decoupled; /* Decoupled volume shading. */
|
||||
bool has_branched_path; /* Supports branched path tracing. */
|
||||
bool has_adaptive_stop_per_sample; /* Per-sample adaptive sampling stopping. */
|
||||
bool has_osl; /* Support Open Shading Language. */
|
||||
bool use_split_kernel; /* Use split or mega kernel. */
|
||||
@@ -99,6 +100,7 @@ class DeviceInfo {
|
||||
display_device = false;
|
||||
has_half_images = false;
|
||||
has_volume_decoupled = false;
|
||||
has_branched_path = true;
|
||||
has_adaptive_stop_per_sample = false;
|
||||
has_osl = false;
|
||||
use_split_kernel = false;
|
||||
|
@@ -920,8 +920,7 @@ class CPUDevice : public Device {
|
||||
ccl_global float *buffer = render_buffer + index * kernel_data.film.pass_stride;
|
||||
if (buffer[kernel_data.film.pass_sample_count] < 0.0f) {
|
||||
buffer[kernel_data.film.pass_sample_count] = -buffer[kernel_data.film.pass_sample_count];
|
||||
float sample_multiplier = tile.sample / max((float)tile.start_sample + 1.0f,
|
||||
buffer[kernel_data.film.pass_sample_count]);
|
||||
float sample_multiplier = tile.sample / buffer[kernel_data.film.pass_sample_count];
|
||||
if (sample_multiplier != 1.0f) {
|
||||
kernel_adaptive_post_adjust(kg, buffer, sample_multiplier);
|
||||
}
|
||||
@@ -952,7 +951,7 @@ class CPUDevice : public Device {
|
||||
SIMD_SET_FLUSH_TO_ZERO;
|
||||
|
||||
for (int sample = start_sample; sample < end_sample; sample++) {
|
||||
if (task.get_cancel() || task_pool.canceled()) {
|
||||
if (task.get_cancel() || TaskPool::canceled()) {
|
||||
if (task.need_finish_queue == false)
|
||||
break;
|
||||
}
|
||||
@@ -997,7 +996,7 @@ class CPUDevice : public Device {
|
||||
coverage.finalize();
|
||||
}
|
||||
|
||||
if (task.adaptive_sampling.use) {
|
||||
if (task.adaptive_sampling.use && (tile.stealing_state != RenderTile::WAS_STOLEN)) {
|
||||
adaptive_sampling_post(tile, kg);
|
||||
}
|
||||
}
|
||||
@@ -1250,7 +1249,7 @@ class CPUDevice : public Device {
|
||||
|
||||
void thread_render(DeviceTask &task)
|
||||
{
|
||||
if (task_pool.canceled()) {
|
||||
if (TaskPool::canceled()) {
|
||||
if (task.need_finish_queue == false)
|
||||
return;
|
||||
}
|
||||
@@ -1320,7 +1319,7 @@ class CPUDevice : public Device {
|
||||
|
||||
task.release_tile(tile);
|
||||
|
||||
if (task_pool.canceled()) {
|
||||
if (TaskPool::canceled()) {
|
||||
if (task.need_finish_queue == false)
|
||||
break;
|
||||
}
|
||||
@@ -1417,7 +1416,7 @@ class CPUDevice : public Device {
|
||||
task.offset,
|
||||
sample);
|
||||
|
||||
if (task.get_cancel() || task_pool.canceled())
|
||||
if (task.get_cancel() || TaskPool::canceled())
|
||||
break;
|
||||
|
||||
task.update_progress(NULL);
|
||||
|
@@ -259,6 +259,8 @@ class device_memory {
|
||||
device_ptr original_device_ptr;
|
||||
size_t original_device_size;
|
||||
Device *original_device;
|
||||
bool need_realloc_;
|
||||
bool modified;
|
||||
};
|
||||
|
||||
/* Device Only Memory
|
||||
@@ -329,6 +331,8 @@ template<typename T> class device_vector : public device_memory {
|
||||
{
|
||||
data_type = device_type_traits<T>::data_type;
|
||||
data_elements = device_type_traits<T>::num_elements;
|
||||
modified = true;
|
||||
need_realloc_ = true;
|
||||
|
||||
assert(data_elements > 0);
|
||||
}
|
||||
@@ -347,6 +351,7 @@ template<typename T> class device_vector : public device_memory {
|
||||
device_free();
|
||||
host_free();
|
||||
host_pointer = host_alloc(sizeof(T) * new_size);
|
||||
modified = true;
|
||||
assert(device_pointer == 0);
|
||||
}
|
||||
|
||||
@@ -400,6 +405,19 @@ template<typename T> class device_vector : public device_memory {
|
||||
assert(device_pointer == 0);
|
||||
}
|
||||
|
||||
void give_data(array<T> &to)
|
||||
{
|
||||
device_free();
|
||||
|
||||
to.set_data((T *)host_pointer, data_size);
|
||||
data_size = 0;
|
||||
data_width = 0;
|
||||
data_height = 0;
|
||||
data_depth = 0;
|
||||
host_pointer = 0;
|
||||
assert(device_pointer == 0);
|
||||
}
|
||||
|
||||
/* Free device and host memory. */
|
||||
void free()
|
||||
{
|
||||
@@ -411,10 +429,40 @@ template<typename T> class device_vector : public device_memory {
|
||||
data_height = 0;
|
||||
data_depth = 0;
|
||||
host_pointer = 0;
|
||||
modified = true;
|
||||
need_realloc_ = true;
|
||||
assert(device_pointer == 0);
|
||||
}
|
||||
|
||||
size_t size()
|
||||
void free_if_need_realloc(bool force_free)
|
||||
{
|
||||
if (need_realloc_ || force_free) {
|
||||
free();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_modified() const
|
||||
{
|
||||
return modified;
|
||||
}
|
||||
|
||||
bool need_realloc()
|
||||
{
|
||||
return need_realloc_;
|
||||
}
|
||||
|
||||
void tag_modified()
|
||||
{
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void tag_realloc()
|
||||
{
|
||||
need_realloc_ = true;
|
||||
tag_modified();
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return data_size;
|
||||
}
|
||||
@@ -432,7 +480,24 @@ template<typename T> class device_vector : public device_memory {
|
||||
|
||||
void copy_to_device()
|
||||
{
|
||||
device_copy_to();
|
||||
if (data_size != 0) {
|
||||
device_copy_to();
|
||||
}
|
||||
}
|
||||
|
||||
void copy_to_device_if_modified()
|
||||
{
|
||||
if (!modified) {
|
||||
return;
|
||||
}
|
||||
|
||||
copy_to_device();
|
||||
}
|
||||
|
||||
void clear_modified()
|
||||
{
|
||||
modified = false;
|
||||
need_realloc_ = false;
|
||||
}
|
||||
|
||||
void copy_from_device()
|
||||
|
@@ -151,8 +151,6 @@ string device_opencl_capabilities()
|
||||
platform_ids.resize(num_platforms);
|
||||
opencl_assert(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL));
|
||||
|
||||
typedef char cl_string[1024];
|
||||
|
||||
# define APPEND_INFO(func, id, name, what, type) \
|
||||
do { \
|
||||
type data; \
|
||||
@@ -160,22 +158,33 @@ string device_opencl_capabilities()
|
||||
opencl_assert(func(id, what, sizeof(data), &data, NULL)); \
|
||||
result += string_printf("%s: %s\n", name, to_string(data).c_str()); \
|
||||
} while (false)
|
||||
# define APPEND_STRING_EXTENSION_INFO(func, id, name, what) \
|
||||
# define APPEND_STRING_INFO_IMPL(func, id, name, what, is_optional) \
|
||||
do { \
|
||||
char data[1024] = "\0"; \
|
||||
string value; \
|
||||
size_t length = 0; \
|
||||
if (func(id, what, sizeof(data), &data, &length) == CL_SUCCESS) { \
|
||||
if (length != 0 && data[0] != '\0') { \
|
||||
result += string_printf("%s: %s\n", name, data); \
|
||||
if (func(id, what, 0, NULL, &length) == CL_SUCCESS) { \
|
||||
vector<char> buffer(length + 1); \
|
||||
if (func(id, what, buffer.size(), buffer.data(), NULL) == CL_SUCCESS) { \
|
||||
value = string(buffer.data()); \
|
||||
} \
|
||||
} \
|
||||
if (is_optional && !(length != 0 && value[0] != '\0')) { \
|
||||
break; \
|
||||
} \
|
||||
result += string_printf("%s: %s\n", name, value.c_str()); \
|
||||
} while (false)
|
||||
# define APPEND_PLATFORM_STRING_INFO(id, name, what) \
|
||||
APPEND_STRING_INFO_IMPL(clGetPlatformInfo, id, "\tPlatform " name, what, false)
|
||||
# define APPEND_STRING_EXTENSION_INFO(func, id, name, what) \
|
||||
APPEND_STRING_INFO_IMPL(clGetPlatformInfo, id, "\tPlatform " name, what, true)
|
||||
# define APPEND_PLATFORM_INFO(id, name, what, type) \
|
||||
APPEND_INFO(clGetPlatformInfo, id, "\tPlatform " name, what, type)
|
||||
# define APPEND_DEVICE_INFO(id, name, what, type) \
|
||||
APPEND_INFO(clGetDeviceInfo, id, "\t\t\tDevice " name, what, type)
|
||||
# define APPEND_DEVICE_STRING_INFO(id, name, what) \
|
||||
APPEND_STRING_INFO_IMPL(clGetDeviceInfo, id, "\t\t\tDevice " name, what, false)
|
||||
# define APPEND_DEVICE_STRING_EXTENSION_INFO(id, name, what) \
|
||||
APPEND_STRING_EXTENSION_INFO(clGetDeviceInfo, id, "\t\t\tDevice " name, what)
|
||||
APPEND_STRING_INFO_IMPL(clGetDeviceInfo, id, "\t\t\tDevice " name, what, true)
|
||||
|
||||
vector<cl_device_id> device_ids;
|
||||
for (cl_uint platform = 0; platform < num_platforms; ++platform) {
|
||||
@@ -183,11 +192,11 @@ string device_opencl_capabilities()
|
||||
|
||||
result += string_printf("Platform #%u\n", platform);
|
||||
|
||||
APPEND_PLATFORM_INFO(platform_id, "Name", CL_PLATFORM_NAME, cl_string);
|
||||
APPEND_PLATFORM_INFO(platform_id, "Vendor", CL_PLATFORM_VENDOR, cl_string);
|
||||
APPEND_PLATFORM_INFO(platform_id, "Version", CL_PLATFORM_VERSION, cl_string);
|
||||
APPEND_PLATFORM_INFO(platform_id, "Profile", CL_PLATFORM_PROFILE, cl_string);
|
||||
APPEND_PLATFORM_INFO(platform_id, "Extensions", CL_PLATFORM_EXTENSIONS, cl_string);
|
||||
APPEND_PLATFORM_STRING_INFO(platform_id, "Name", CL_PLATFORM_NAME);
|
||||
APPEND_PLATFORM_STRING_INFO(platform_id, "Vendor", CL_PLATFORM_VENDOR);
|
||||
APPEND_PLATFORM_STRING_INFO(platform_id, "Version", CL_PLATFORM_VERSION);
|
||||
APPEND_PLATFORM_STRING_INFO(platform_id, "Profile", CL_PLATFORM_PROFILE);
|
||||
APPEND_PLATFORM_STRING_INFO(platform_id, "Extensions", CL_PLATFORM_EXTENSIONS);
|
||||
|
||||
cl_uint num_devices = 0;
|
||||
opencl_assert(
|
||||
@@ -202,13 +211,13 @@ string device_opencl_capabilities()
|
||||
|
||||
result += string_printf("\t\tDevice: #%u\n", device);
|
||||
|
||||
APPEND_DEVICE_INFO(device_id, "Name", CL_DEVICE_NAME, cl_string);
|
||||
APPEND_DEVICE_STRING_INFO(device_id, "Name", CL_DEVICE_NAME);
|
||||
APPEND_DEVICE_STRING_EXTENSION_INFO(device_id, "Board Name", CL_DEVICE_BOARD_NAME_AMD);
|
||||
APPEND_DEVICE_INFO(device_id, "Vendor", CL_DEVICE_VENDOR, cl_string);
|
||||
APPEND_DEVICE_INFO(device_id, "OpenCL C Version", CL_DEVICE_OPENCL_C_VERSION, cl_string);
|
||||
APPEND_DEVICE_INFO(device_id, "Profile", CL_DEVICE_PROFILE, cl_string);
|
||||
APPEND_DEVICE_INFO(device_id, "Version", CL_DEVICE_VERSION, cl_string);
|
||||
APPEND_DEVICE_INFO(device_id, "Extensions", CL_DEVICE_EXTENSIONS, cl_string);
|
||||
APPEND_DEVICE_STRING_INFO(device_id, "Vendor", CL_DEVICE_VENDOR);
|
||||
APPEND_DEVICE_STRING_INFO(device_id, "OpenCL C Version", CL_DEVICE_OPENCL_C_VERSION);
|
||||
APPEND_DEVICE_STRING_INFO(device_id, "Profile", CL_DEVICE_PROFILE);
|
||||
APPEND_DEVICE_STRING_INFO(device_id, "Version", CL_DEVICE_VERSION);
|
||||
APPEND_DEVICE_STRING_INFO(device_id, "Extensions", CL_DEVICE_EXTENSIONS);
|
||||
APPEND_DEVICE_INFO(
|
||||
device_id, "Max clock frequency (MHz)", CL_DEVICE_MAX_CLOCK_FREQUENCY, cl_uint);
|
||||
APPEND_DEVICE_INFO(device_id, "Max compute units", CL_DEVICE_MAX_COMPUTE_UNITS, cl_uint);
|
||||
@@ -216,9 +225,14 @@ string device_opencl_capabilities()
|
||||
}
|
||||
}
|
||||
|
||||
# undef APPEND_STRING_INFO
|
||||
# undef APPEND_INFO
|
||||
# undef APPEND_STRING_INFO_IMPL
|
||||
# undef APPEND_PLATFORM_STRING_INFO
|
||||
# undef APPEND_STRING_EXTENSION_INFO
|
||||
# undef APPEND_PLATFORM_INFO
|
||||
# undef APPEND_DEVICE_INFO
|
||||
# undef APPEND_DEVICE_STRING_INFO
|
||||
# undef APPEND_DEVICE_STRING_EXTENSION_INFO
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@@ -760,9 +760,6 @@ class OptiXDevice : public CUDADevice {
|
||||
const int end_sample = rtile.start_sample + rtile.num_samples;
|
||||
// Keep this number reasonable to avoid running into TDRs
|
||||
int step_samples = (info.display_device ? 8 : 32);
|
||||
if (task.adaptive_sampling.use) {
|
||||
step_samples = task.adaptive_sampling.align_static_samples(step_samples);
|
||||
}
|
||||
|
||||
// Offset into launch params buffer so that streams use separate data
|
||||
device_ptr launch_params_ptr = launch_params.device_pointer +
|
||||
@@ -770,10 +767,14 @@ class OptiXDevice : public CUDADevice {
|
||||
|
||||
const CUDAContextScope scope(cuContext);
|
||||
|
||||
for (int sample = rtile.start_sample; sample < end_sample; sample += step_samples) {
|
||||
for (int sample = rtile.start_sample; sample < end_sample;) {
|
||||
// Copy work tile information to device
|
||||
wtile.num_samples = min(step_samples, end_sample - sample);
|
||||
wtile.start_sample = sample;
|
||||
wtile.num_samples = step_samples;
|
||||
if (task.adaptive_sampling.use) {
|
||||
wtile.num_samples = task.adaptive_sampling.align_samples(sample, step_samples);
|
||||
}
|
||||
wtile.num_samples = min(wtile.num_samples, end_sample - sample);
|
||||
device_ptr d_wtile_ptr = launch_params_ptr + offsetof(KernelParams, tile);
|
||||
check_result_cuda(
|
||||
cuMemcpyHtoDAsync(d_wtile_ptr, &wtile, sizeof(wtile), cuda_stream[thread_index]));
|
||||
@@ -815,7 +816,8 @@ class OptiXDevice : public CUDADevice {
|
||||
check_result_cuda(cuStreamSynchronize(cuda_stream[thread_index]));
|
||||
|
||||
// Update current sample, so it is displayed correctly
|
||||
rtile.sample = wtile.start_sample + wtile.num_samples;
|
||||
sample += wtile.num_samples;
|
||||
rtile.sample = sample;
|
||||
// Update task progress after the kernel completed rendering
|
||||
task.update_progress(&rtile, wtile.w * wtile.h * wtile.num_samples);
|
||||
|
||||
@@ -1855,6 +1857,7 @@ void device_optix_info(const vector<DeviceInfo> &cuda_devices, vector<DeviceInfo
|
||||
info.type = DEVICE_OPTIX;
|
||||
info.id += "_OptiX";
|
||||
info.denoisers |= DENOISER_OPTIX;
|
||||
info.has_branched_path = false;
|
||||
|
||||
devices.push_back(info);
|
||||
}
|
||||
|
@@ -223,8 +223,8 @@ bool DeviceSplitKernel::path_trace(DeviceTask &task,
|
||||
subtile.num_samples = samples_per_second;
|
||||
|
||||
if (task.adaptive_sampling.use) {
|
||||
subtile.num_samples = task.adaptive_sampling.align_dynamic_samples(subtile.start_sample,
|
||||
subtile.num_samples);
|
||||
subtile.num_samples = task.adaptive_sampling.align_samples(subtile.start_sample,
|
||||
subtile.num_samples);
|
||||
}
|
||||
|
||||
/* Don't go beyond requested number of samples. */
|
||||
|
@@ -144,41 +144,20 @@ AdaptiveSampling::AdaptiveSampling() : use(true), adaptive_step(0), min_samples(
|
||||
}
|
||||
|
||||
/* Render samples in steps that align with the adaptive filtering. */
|
||||
int AdaptiveSampling::align_static_samples(int samples) const
|
||||
int AdaptiveSampling::align_samples(int sample, int num_samples) const
|
||||
{
|
||||
if (samples > adaptive_step) {
|
||||
/* Make multiple of adaptive_step. */
|
||||
while (samples % adaptive_step != 0) {
|
||||
samples--;
|
||||
}
|
||||
int end_sample = sample + num_samples;
|
||||
|
||||
/* Round down end sample to the nearest sample that needs filtering. */
|
||||
end_sample &= ~(adaptive_step - 1);
|
||||
|
||||
if (end_sample <= sample) {
|
||||
/* In order to reach the next sample that needs filtering, we'd need
|
||||
* to increase num_samples. We don't do that in this function, so
|
||||
* just keep it as is and don't filter this time around. */
|
||||
return num_samples;
|
||||
}
|
||||
else if (samples < adaptive_step) {
|
||||
/* Make divisor of adaptive_step. */
|
||||
while (adaptive_step % samples != 0) {
|
||||
samples--;
|
||||
}
|
||||
}
|
||||
|
||||
return max(samples, 1);
|
||||
}
|
||||
|
||||
/* Render samples in steps that align with the adaptive filtering, with the
|
||||
* suggested number of samples dynamically changing. */
|
||||
int AdaptiveSampling::align_dynamic_samples(int offset, int samples) const
|
||||
{
|
||||
/* Round so that we end up on multiples of adaptive_samples. */
|
||||
samples += offset;
|
||||
|
||||
if (samples > adaptive_step) {
|
||||
/* Make multiple of adaptive_step. */
|
||||
while (samples % adaptive_step != 0) {
|
||||
samples--;
|
||||
}
|
||||
}
|
||||
|
||||
samples -= offset;
|
||||
|
||||
return max(samples, 1);
|
||||
return end_sample - sample;
|
||||
}
|
||||
|
||||
bool AdaptiveSampling::need_filter(int sample) const
|
||||
|
@@ -117,8 +117,7 @@ class AdaptiveSampling {
|
||||
public:
|
||||
AdaptiveSampling();
|
||||
|
||||
int align_static_samples(int samples) const;
|
||||
int align_dynamic_samples(int offset, int samples) const;
|
||||
int align_samples(int sample, int num_samples) const;
|
||||
bool need_filter(int sample) const;
|
||||
|
||||
bool use;
|
||||
|
@@ -454,7 +454,7 @@ ccl_device_inline bool cylinder_culling_test(const float2 p1, const float2 p2, c
|
||||
/* Performs culling against a cylinder. */
|
||||
const float2 dp = p2 - p1;
|
||||
const float num = dp.x * p1.y - dp.y * p1.x;
|
||||
const float den2 = dot(p2 - p1, p2 - p1);
|
||||
const float den2 = dot(dp, dp);
|
||||
return num * num <= r * r * den2;
|
||||
}
|
||||
|
||||
@@ -571,46 +571,46 @@ ccl_device_inline bool ribbon_intersect(const float3 ray_org,
|
||||
for (int i = 0; i < N; i++) {
|
||||
const float u = i * step_size;
|
||||
const float4 p1 = catmull_rom_basis_eval(curve, u + step_size);
|
||||
bool valid = cylinder_culling_test(
|
||||
const bool valid = cylinder_culling_test(
|
||||
make_float2(p0.x, p0.y), make_float2(p1.x, p1.y), max(p0.w, p1.w));
|
||||
if (!valid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Evaluate next point. */
|
||||
float3 dp1dt = float4_to_float3(catmull_rom_basis_derivative(curve, u + step_size));
|
||||
dp1dt = (max3(fabs(dp1dt)) < eps) ? float4_to_float3(p1 - p0) : dp1dt;
|
||||
const float3 wn1 = normalize(make_float3(dp1dt.y, -dp1dt.x, 0.0f)) * p1.w;
|
||||
|
||||
/* Construct quad coordinates. */
|
||||
const float3 lp0 = float4_to_float3(p0) + wn0;
|
||||
const float3 lp1 = float4_to_float3(p1) + wn1;
|
||||
const float3 up0 = float4_to_float3(p0) - wn0;
|
||||
const float3 up1 = float4_to_float3(p1) - wn1;
|
||||
if (valid) {
|
||||
/* Construct quad coordinates. */
|
||||
const float3 lp0 = float4_to_float3(p0) + wn0;
|
||||
const float3 lp1 = float4_to_float3(p1) + wn1;
|
||||
const float3 up0 = float4_to_float3(p0) - wn0;
|
||||
const float3 up1 = float4_to_float3(p1) - wn1;
|
||||
|
||||
/* Intersect quad. */
|
||||
float vu, vv, vt;
|
||||
bool valid0 = ribbon_intersect_quad(isect->t, lp0, lp1, up1, up0, &vu, &vv, &vt);
|
||||
|
||||
if (valid0) {
|
||||
/* ignore self intersections */
|
||||
const float avoidance_factor = 2.0f;
|
||||
if (avoidance_factor != 0.0f) {
|
||||
float r = mix(p0.w, p1.w, vu);
|
||||
valid0 = vt > avoidance_factor * r;
|
||||
}
|
||||
/* Intersect quad. */
|
||||
float vu, vv, vt;
|
||||
bool valid0 = ribbon_intersect_quad(isect->t, lp0, lp1, up1, up0, &vu, &vv, &vt);
|
||||
|
||||
if (valid0) {
|
||||
vv = 2.0f * vv - 1.0f;
|
||||
/* ignore self intersections */
|
||||
const float avoidance_factor = 2.0f;
|
||||
if (avoidance_factor != 0.0f) {
|
||||
float r = mix(p0.w, p1.w, vu);
|
||||
valid0 = vt > avoidance_factor * r;
|
||||
}
|
||||
|
||||
/* Record intersection. */
|
||||
isect->t = vt;
|
||||
isect->u = u + vu * step_size;
|
||||
isect->v = vv;
|
||||
return true;
|
||||
if (valid0) {
|
||||
vv = 2.0f * vv - 1.0f;
|
||||
|
||||
/* Record intersection. */
|
||||
isect->t = vt;
|
||||
isect->u = u + vu * step_size;
|
||||
isect->v = vv;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Store point for next step. */
|
||||
p0 = p1;
|
||||
wn0 = wn1;
|
||||
}
|
||||
|
@@ -139,7 +139,7 @@ kernel_cuda_adaptive_scale_samples(WorkTile *tile, int start_sample, int sample,
|
||||
ccl_global float *buffer = tile->buffer + index * kernel_data.film.pass_stride;
|
||||
if(buffer[kernel_data.film.pass_sample_count] < 0.0f) {
|
||||
buffer[kernel_data.film.pass_sample_count] = -buffer[kernel_data.film.pass_sample_count];
|
||||
float sample_multiplier = sample / max((float)start_sample + 1.0f, buffer[kernel_data.film.pass_sample_count]);
|
||||
float sample_multiplier = sample / buffer[kernel_data.film.pass_sample_count];
|
||||
if(sample_multiplier != 1.0f) {
|
||||
kernel_adaptive_post_adjust(&kg, buffer, sample_multiplier);
|
||||
}
|
||||
|
@@ -15,7 +15,20 @@
|
||||
*/
|
||||
|
||||
#ifdef WITH_NANOVDB
|
||||
/* Data type to replace `double` used in the NanoVDB headers. Cycles don't need doubles, and is
|
||||
* safer and more portable to never use double datatype on GPU.
|
||||
* Use a special structure, so that the following is true:
|
||||
* - No unnoticed implicit cast or mathematical operations used on scalar 64bit type
|
||||
* (which rules out trick like using `uint64_t` as a drop-in replacement for double).
|
||||
* - Padding rules are matching exactly `double`
|
||||
* (which rules out array of `uint8_t`). */
|
||||
typedef struct ccl_vdb_double_t {
|
||||
uint64_t i;
|
||||
} ccl_vdb_double_t;
|
||||
|
||||
# define double ccl_vdb_double_t
|
||||
# include "nanovdb/CNanoVDB.h"
|
||||
# undef double
|
||||
#endif
|
||||
|
||||
/* For OpenCL we do manual lookup and interpolation. */
|
||||
|
@@ -43,7 +43,7 @@ class ColorSpaceProcessor;
|
||||
*
|
||||
* Data needed by OSL render services, that is global to a rendering session.
|
||||
* This includes all OSL shaders, name to attribute mapping and texture handles.
|
||||
* */
|
||||
*/
|
||||
|
||||
struct OSLGlobals {
|
||||
OSLGlobals()
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <OSL/oslclosure.h>
|
||||
#include <OSL/oslexec.h>
|
||||
#include <OSL/rendererservices.h>
|
||||
|
||||
#ifdef WITH_PTEX
|
||||
class PtexCache;
|
||||
|
@@ -29,8 +29,7 @@ ccl_device void kernel_adaptive_adjust_samples(KernelGlobals *kg)
|
||||
int sample = kernel_split_params.tile.start_sample + kernel_split_params.tile.num_samples;
|
||||
if (buffer[kernel_data.film.pass_sample_count] < 0.0f) {
|
||||
buffer[kernel_data.film.pass_sample_count] = -buffer[kernel_data.film.pass_sample_count];
|
||||
float sample_multiplier = sample / max((float)kernel_split_params.tile.start_sample + 1.0f,
|
||||
buffer[kernel_data.film.pass_sample_count]);
|
||||
float sample_multiplier = sample / buffer[kernel_data.film.pass_sample_count];
|
||||
if (sample_multiplier != 1.0f) {
|
||||
kernel_adaptive_post_adjust(kg, buffer, sample_multiplier);
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@ set(INC_SYS
|
||||
)
|
||||
|
||||
set(SRC
|
||||
alembic.cpp
|
||||
attribute.cpp
|
||||
background.cpp
|
||||
bake.cpp
|
||||
@@ -48,6 +49,7 @@ set(SRC
|
||||
mesh_displace.cpp
|
||||
mesh_subdivision.cpp
|
||||
nodes.cpp
|
||||
procedural.cpp
|
||||
object.cpp
|
||||
osl.cpp
|
||||
particles.cpp
|
||||
@@ -64,6 +66,7 @@ set(SRC
|
||||
)
|
||||
|
||||
set(SRC_HEADERS
|
||||
alembic.h
|
||||
attribute.h
|
||||
bake.h
|
||||
background.h
|
||||
@@ -90,6 +93,7 @@ set(SRC_HEADERS
|
||||
object.h
|
||||
osl.h
|
||||
particles.h
|
||||
procedural.h
|
||||
curves.h
|
||||
scene.h
|
||||
session.h
|
||||
@@ -144,6 +148,16 @@ if(WITH_OPENVDB)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
add_definitions(-DWITH_ALEMBIC)
|
||||
list(APPEND INC_SYS
|
||||
${ALEMBIC_INCLUDE_DIRS}
|
||||
)
|
||||
list(APPEND LIB
|
||||
${ALEMBIC_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_NANOVDB)
|
||||
list(APPEND INC_SYS
|
||||
${NANOVDB_INCLUDE_DIRS}
|
||||
|
1869
intern/cycles/render/alembic.cpp
Normal file
1869
intern/cycles/render/alembic.cpp
Normal file
File diff suppressed because it is too large
Load Diff
404
intern/cycles/render/alembic.h
Normal file
404
intern/cycles/render/alembic.h
Normal file
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Copyright 2011-2018 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "graph/node.h"
|
||||
#include "render/attribute.h"
|
||||
#include "render/procedural.h"
|
||||
#include "util/util_set.h"
|
||||
#include "util/util_transform.h"
|
||||
#include "util/util_vector.h"
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
|
||||
# include <Alembic/AbcCoreFactory/All.h>
|
||||
# include <Alembic/AbcGeom/All.h>
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class AlembicProcedural;
|
||||
class Geometry;
|
||||
class Object;
|
||||
class Progress;
|
||||
class Shader;
|
||||
|
||||
using MatrixSampleMap = std::map<Alembic::Abc::chrono_t, Alembic::Abc::M44d>;
|
||||
|
||||
/* Helpers to detect if some type is a ccl::array. */
|
||||
template<typename> struct is_array : public std::false_type {
|
||||
};
|
||||
|
||||
template<typename T> struct is_array<array<T>> : public std::true_type {
|
||||
};
|
||||
|
||||
/* Store the data set for an animation at every time points, or at the beginning of the animation
|
||||
* for constant data.
|
||||
*
|
||||
* The data is supposed to be stored in chronological order, and is looked up using the current
|
||||
* animation time in seconds using the TimeSampling from the Alembic property. */
|
||||
template<typename T> class DataStore {
|
||||
struct DataTimePair {
|
||||
double time = 0;
|
||||
T data{};
|
||||
};
|
||||
|
||||
vector<DataTimePair> data{};
|
||||
Alembic::AbcCoreAbstract::TimeSampling time_sampling{};
|
||||
|
||||
double last_loaded_time = std::numeric_limits<double>::max();
|
||||
|
||||
public:
|
||||
void set_time_sampling(Alembic::AbcCoreAbstract::TimeSampling time_sampling_)
|
||||
{
|
||||
time_sampling = time_sampling_;
|
||||
}
|
||||
|
||||
Alembic::AbcCoreAbstract::TimeSampling get_time_sampling() const
|
||||
{
|
||||
return time_sampling;
|
||||
}
|
||||
|
||||
/* Get the data for the specified time.
|
||||
* Return nullptr if there is no data or if the data for this time was already loaded. */
|
||||
T *data_for_time(double time)
|
||||
{
|
||||
if (size() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::pair<size_t, Alembic::Abc::chrono_t> index_pair;
|
||||
index_pair = time_sampling.getNearIndex(time, data.size());
|
||||
DataTimePair &data_pair = data[index_pair.first];
|
||||
|
||||
if (last_loaded_time == data_pair.time) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
last_loaded_time = data_pair.time;
|
||||
|
||||
return &data_pair.data;
|
||||
}
|
||||
|
||||
/* get the data for the specified time, but do not check if the data was already loaded for this
|
||||
* time return nullptr if there is no data */
|
||||
T *data_for_time_no_check(double time)
|
||||
{
|
||||
if (size() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::pair<size_t, Alembic::Abc::chrono_t> index_pair;
|
||||
index_pair = time_sampling.getNearIndex(time, data.size());
|
||||
DataTimePair &data_pair = data[index_pair.first];
|
||||
return &data_pair.data;
|
||||
}
|
||||
|
||||
void add_data(T &data_, double time)
|
||||
{
|
||||
if constexpr (is_array<T>::value) {
|
||||
data.emplace_back();
|
||||
data.back().data.steal_data(data_);
|
||||
data.back().time = time;
|
||||
return;
|
||||
}
|
||||
|
||||
data.push_back({time, data_});
|
||||
}
|
||||
|
||||
bool is_constant() const
|
||||
{
|
||||
return data.size() <= 1;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return data.size();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
invalidate_last_loaded_time();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
void invalidate_last_loaded_time()
|
||||
{
|
||||
last_loaded_time = std::numeric_limits<double>::max();
|
||||
}
|
||||
|
||||
/* Copy the data for the specified time to the node's socket. If there is no
|
||||
* data for this time or it was already loaded, do nothing. */
|
||||
void copy_to_socket(double time, Node *node, const SocketType *socket)
|
||||
{
|
||||
T *data_ = data_for_time(time);
|
||||
|
||||
if (data_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO(@kevindietrich): arrays are emptied when passed to the sockets, so for now we copy the
|
||||
* arrays to avoid reloading the data */
|
||||
T value = *data_;
|
||||
node->set(*socket, value);
|
||||
}
|
||||
};
|
||||
|
||||
/* Actual cache for the stored data.
|
||||
* This caches the topological, transformation, and attribute data for a Mesh node or a Hair node
|
||||
* inside of DataStores.
|
||||
*/
|
||||
struct CachedData {
|
||||
DataStore<Transform> transforms{};
|
||||
|
||||
/* mesh data */
|
||||
DataStore<array<float3>> vertices;
|
||||
DataStore<array<int3>> triangles{};
|
||||
/* triangle "loops" are the polygons' vertices indices used for indexing face varying attributes
|
||||
* (like UVs) */
|
||||
DataStore<array<int3>> triangles_loops{};
|
||||
DataStore<array<int>> shader{};
|
||||
|
||||
/* subd data */
|
||||
DataStore<array<int>> subd_start_corner;
|
||||
DataStore<array<int>> subd_num_corners;
|
||||
DataStore<array<bool>> subd_smooth;
|
||||
DataStore<array<int>> subd_ptex_offset;
|
||||
DataStore<array<int>> subd_face_corners;
|
||||
DataStore<int> num_ngons;
|
||||
DataStore<array<int>> subd_creases_edge;
|
||||
DataStore<array<float>> subd_creases_weight;
|
||||
|
||||
/* hair data */
|
||||
DataStore<array<float3>> curve_keys;
|
||||
DataStore<array<float>> curve_radius;
|
||||
DataStore<array<int>> curve_first_key;
|
||||
DataStore<array<int>> curve_shader;
|
||||
|
||||
struct CachedAttribute {
|
||||
AttributeStandard std;
|
||||
AttributeElement element;
|
||||
TypeDesc type_desc;
|
||||
ustring name;
|
||||
DataStore<array<char>> data{};
|
||||
};
|
||||
|
||||
vector<CachedAttribute> attributes{};
|
||||
|
||||
void clear();
|
||||
|
||||
CachedAttribute &add_attribute(const ustring &name,
|
||||
const Alembic::Abc::TimeSampling &time_sampling);
|
||||
|
||||
bool is_constant() const;
|
||||
|
||||
void invalidate_last_loaded_time(bool attributes_only = false);
|
||||
|
||||
void set_time_sampling(Alembic::AbcCoreAbstract::TimeSampling time_sampling);
|
||||
};
|
||||
|
||||
/* Representation of an Alembic object for the AlembicProcedural.
|
||||
*
|
||||
* The AlembicObject holds the path to the Alembic IObject inside of the archive that is desired
|
||||
* for rendering, as well as the list of shaders that it is using.
|
||||
*
|
||||
* The names of the shaders should correspond to the names of the FaceSets inside of the Alembic
|
||||
* archive for per-triangle shader association. If there is no FaceSets, or the names do not
|
||||
* match, the first shader is used for rendering for all triangles.
|
||||
*/
|
||||
class AlembicObject : public Node {
|
||||
public:
|
||||
NODE_DECLARE
|
||||
|
||||
/* Path to the IObject inside of the archive. */
|
||||
NODE_SOCKET_API(ustring, path)
|
||||
|
||||
/* Shaders used for rendering. */
|
||||
NODE_SOCKET_API_ARRAY(array<Node *>, used_shaders)
|
||||
|
||||
/* Maximum number of subdivisions for ISubD objects. */
|
||||
NODE_SOCKET_API(int, subd_max_level)
|
||||
|
||||
/* Finest level of detail (in pixels) for the subdivision. */
|
||||
NODE_SOCKET_API(float, subd_dicing_rate)
|
||||
|
||||
/* Scale the radius of points and curves. */
|
||||
NODE_SOCKET_API(float, radius_scale)
|
||||
|
||||
AlembicObject();
|
||||
~AlembicObject();
|
||||
|
||||
private:
|
||||
friend class AlembicProcedural;
|
||||
|
||||
void set_object(Object *object);
|
||||
Object *get_object();
|
||||
|
||||
void load_all_data(AlembicProcedural *proc,
|
||||
Alembic::AbcGeom::IPolyMeshSchema &schema,
|
||||
float scale,
|
||||
Progress &progress);
|
||||
void load_all_data(AlembicProcedural *proc,
|
||||
Alembic::AbcGeom::ISubDSchema &schema,
|
||||
float scale,
|
||||
Progress &progress);
|
||||
void load_all_data(AlembicProcedural *proc,
|
||||
const Alembic::AbcGeom::ICurvesSchema &schema,
|
||||
float scale,
|
||||
Progress &progress,
|
||||
float default_radius);
|
||||
|
||||
bool has_data_loaded() const;
|
||||
|
||||
bool need_shader_update = true;
|
||||
|
||||
MatrixSampleMap xform_samples;
|
||||
Alembic::AbcGeom::IObject iobject;
|
||||
Transform xform;
|
||||
|
||||
CachedData &get_cached_data()
|
||||
{
|
||||
return cached_data;
|
||||
}
|
||||
|
||||
bool is_constant() const
|
||||
{
|
||||
return cached_data.is_constant();
|
||||
}
|
||||
|
||||
Object *object = nullptr;
|
||||
|
||||
bool data_loaded = false;
|
||||
|
||||
CachedData cached_data;
|
||||
|
||||
void update_shader_attributes(const Alembic::AbcGeom::ICompoundProperty &arb_geom_params,
|
||||
Progress &progress);
|
||||
|
||||
void read_attribute(const Alembic::AbcGeom::ICompoundProperty &arb_geom_params,
|
||||
const ustring &attr_name,
|
||||
Progress &progress);
|
||||
|
||||
template<typename SchemaType>
|
||||
void read_face_sets(SchemaType &schema,
|
||||
array<int> &polygon_to_shader,
|
||||
Alembic::AbcGeom::ISampleSelector sample_sel);
|
||||
|
||||
void setup_transform_cache(float scale);
|
||||
|
||||
AttributeRequestSet get_requested_attributes();
|
||||
};
|
||||
|
||||
/* Procedural to render objects from a single Alembic archive.
|
||||
*
|
||||
* Every object desired to be rendered should be passed as an AlembicObject through the objects
|
||||
* socket.
|
||||
*
|
||||
* This procedural will load the data set for the entire animation in memory on the first frame,
|
||||
* and directly set the data for the new frames on the created Nodes if needed. This allows for
|
||||
* faster updates between frames as it avoids reseeking the data on disk.
|
||||
*/
|
||||
class AlembicProcedural : public Procedural {
|
||||
Alembic::AbcGeom::IArchive archive;
|
||||
bool objects_loaded;
|
||||
Scene *scene_;
|
||||
|
||||
public:
|
||||
NODE_DECLARE
|
||||
|
||||
/* The file path to the Alembic archive */
|
||||
NODE_SOCKET_API(ustring, filepath)
|
||||
|
||||
/* The current frame to render. */
|
||||
NODE_SOCKET_API(float, frame)
|
||||
|
||||
/* The first frame to load data for. */
|
||||
NODE_SOCKET_API(float, start_frame)
|
||||
|
||||
/* The last frame to load data for. */
|
||||
NODE_SOCKET_API(float, end_frame)
|
||||
|
||||
/* Subtracted to the current frame. */
|
||||
NODE_SOCKET_API(float, frame_offset)
|
||||
|
||||
/* The frame rate used for rendering in units of frames per second. */
|
||||
NODE_SOCKET_API(float, frame_rate)
|
||||
|
||||
/* List of AlembicObjects to render. */
|
||||
NODE_SOCKET_API_ARRAY(array<Node *>, objects)
|
||||
|
||||
/* Set the default radius to use for curves when the Alembic Curves Schemas do not have radius
|
||||
* information. */
|
||||
NODE_SOCKET_API(float, default_radius)
|
||||
|
||||
/* Multiplier to account for differences in default units for measuring objects in various
|
||||
* software. */
|
||||
NODE_SOCKET_API(float, scale)
|
||||
|
||||
AlembicProcedural();
|
||||
~AlembicProcedural();
|
||||
|
||||
/* Populates the Cycles scene with Nodes for every contained AlembicObject on the first
|
||||
* invocation, and updates the data on subsequent invocations if the frame changed. */
|
||||
void generate(Scene *scene, Progress &progress);
|
||||
|
||||
/* Add an object to our list of objects, and tag the socket as modified. */
|
||||
void add_object(AlembicObject *object);
|
||||
|
||||
/* Tag for an update only if something was modified. */
|
||||
void tag_update(Scene *scene);
|
||||
|
||||
/* Returns a pointer to an exisiting or a newly created AlembicObject for the given path. */
|
||||
AlembicObject *get_or_create_object(const ustring &path);
|
||||
|
||||
private:
|
||||
/* Load the data for all the objects whose data has not yet been loaded. */
|
||||
void load_objects(Progress &progress);
|
||||
|
||||
/* Traverse the Alembic hierarchy to lookup the IObjects for the AlembicObjects that were
|
||||
* specified in our objects socket, and accumulate all of the transformations samples along the
|
||||
* way for each IObject. */
|
||||
void walk_hierarchy(Alembic::AbcGeom::IObject parent,
|
||||
const Alembic::AbcGeom::ObjectHeader &ohead,
|
||||
MatrixSampleMap *xform_samples,
|
||||
const unordered_map<string, AlembicObject *> &object_map,
|
||||
Progress &progress);
|
||||
|
||||
/* Read the data for an IPolyMesh at the specified frame_time. Creates corresponding Geometry and
|
||||
* Object Nodes in the Cycles scene if none exist yet. */
|
||||
void read_mesh(Scene *scene,
|
||||
AlembicObject *abc_object,
|
||||
Alembic::AbcGeom::Abc::chrono_t frame_time,
|
||||
Progress &progress);
|
||||
|
||||
/* Read the data for an ICurves at the specified frame_time. Creates corresponding Geometry and
|
||||
* Object Nodes in the Cycles scene if none exist yet. */
|
||||
void read_curves(Scene *scene,
|
||||
AlembicObject *abc_object,
|
||||
Alembic::AbcGeom::Abc::chrono_t frame_time,
|
||||
Progress &progress);
|
||||
|
||||
/* Read the data for an ISubD at the specified frame_time. Creates corresponding Geometry and
|
||||
* Object Nodes in the Cycles scene if none exist yet. */
|
||||
void read_subd(Scene *scene,
|
||||
AlembicObject *abc_object,
|
||||
Alembic::AbcGeom::Abc::chrono_t frame_time,
|
||||
Progress &progress);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif
|
@@ -28,7 +28,7 @@ CCL_NAMESPACE_BEGIN
|
||||
|
||||
Attribute::Attribute(
|
||||
ustring name, TypeDesc type, AttributeElement element, Geometry *geom, AttributePrimitive prim)
|
||||
: name(name), std(ATTR_STD_NONE), type(type), element(element), flags(0)
|
||||
: name(name), std(ATTR_STD_NONE), type(type), element(element), flags(0), modified(true)
|
||||
{
|
||||
/* string and matrix not supported! */
|
||||
assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor ||
|
||||
@@ -82,6 +82,8 @@ void Attribute::add(const float &f)
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buffer.push_back(data[i]);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void Attribute::add(const uchar4 &f)
|
||||
@@ -93,6 +95,8 @@ void Attribute::add(const uchar4 &f)
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buffer.push_back(data[i]);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void Attribute::add(const float2 &f)
|
||||
@@ -104,6 +108,8 @@ void Attribute::add(const float2 &f)
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buffer.push_back(data[i]);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void Attribute::add(const float3 &f)
|
||||
@@ -115,6 +121,8 @@ void Attribute::add(const float3 &f)
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buffer.push_back(data[i]);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void Attribute::add(const Transform &f)
|
||||
@@ -126,6 +134,8 @@ void Attribute::add(const Transform &f)
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buffer.push_back(data[i]);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void Attribute::add(const char *data)
|
||||
@@ -134,6 +144,26 @@ void Attribute::add(const char *data)
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buffer.push_back(data[i]);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void Attribute::set_data_from(Attribute &&other)
|
||||
{
|
||||
assert(other.std == std);
|
||||
assert(other.type == type);
|
||||
assert(other.element == element);
|
||||
|
||||
this->flags = other.flags;
|
||||
|
||||
if (this->buffer.size() != other.buffer.size()) {
|
||||
this->buffer = std::move(other.buffer);
|
||||
modified = true;
|
||||
}
|
||||
else if (memcmp(this->data(), other.data(), other.buffer.size()) != 0) {
|
||||
this->buffer = std::move(other.buffer);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
size_t Attribute::data_sizeof() const
|
||||
@@ -627,6 +657,42 @@ void AttributeSet::clear(bool preserve_voxel_data)
|
||||
}
|
||||
}
|
||||
|
||||
void AttributeSet::update(AttributeSet &&new_attributes)
|
||||
{
|
||||
/* add or update old_attributes based on the new_attributes */
|
||||
foreach (Attribute &attr, new_attributes.attributes) {
|
||||
Attribute *nattr = add(attr.name, attr.type, attr.element);
|
||||
nattr->std = attr.std;
|
||||
nattr->set_data_from(std::move(attr));
|
||||
}
|
||||
|
||||
/* remove any attributes not on new_attributes */
|
||||
list<Attribute>::iterator it;
|
||||
for (it = attributes.begin(); it != attributes.end();) {
|
||||
if (it->std != ATTR_STD_NONE) {
|
||||
if (new_attributes.find(it->std) == nullptr) {
|
||||
attributes.erase(it++);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (it->name != "") {
|
||||
if (new_attributes.find(it->name) == nullptr) {
|
||||
attributes.erase(it++);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
void AttributeSet::clear_modified()
|
||||
{
|
||||
foreach (Attribute &attr, attributes) {
|
||||
attr.modified = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* AttributeRequest */
|
||||
|
||||
AttributeRequest::AttributeRequest(ustring name_)
|
||||
|
@@ -54,6 +54,8 @@ class Attribute {
|
||||
AttributeElement element;
|
||||
uint flags; /* enum AttributeFlag */
|
||||
|
||||
bool modified;
|
||||
|
||||
Attribute(ustring name,
|
||||
TypeDesc type,
|
||||
AttributeElement element,
|
||||
@@ -159,6 +161,8 @@ class Attribute {
|
||||
void add(const Transform &tfm);
|
||||
void add(const char *data);
|
||||
|
||||
void set_data_from(Attribute &&other);
|
||||
|
||||
static bool same_storage(TypeDesc a, TypeDesc b);
|
||||
static const char *standard_name(AttributeStandard std);
|
||||
static AttributeStandard name_standard(const char *name);
|
||||
@@ -194,6 +198,12 @@ class AttributeSet {
|
||||
|
||||
void resize(bool reserve_only = false);
|
||||
void clear(bool preserve_voxel_data = false);
|
||||
|
||||
/* Update the attributes in this AttributeSet with the ones from the new set,
|
||||
* and remove any attribute not found on the new set from this. */
|
||||
void update(AttributeSet &&new_attributes);
|
||||
|
||||
void clear_modified();
|
||||
};
|
||||
|
||||
/* AttributeRequest
|
||||
|
@@ -130,8 +130,9 @@ void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
|
||||
|
||||
void Background::tag_update(Scene *scene)
|
||||
{
|
||||
scene->integrator->tag_update(scene);
|
||||
tag_modified();
|
||||
if (ao_factor_is_modified() || use_ao_is_modified()) {
|
||||
scene->integrator->tag_update(scene, Integrator::BACKGROUND_AO_MODIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
Shader *Background::get_shader(const Scene *scene)
|
||||
|
@@ -78,7 +78,7 @@ BakeManager::BakeManager()
|
||||
type = SHADER_EVAL_BAKE;
|
||||
pass_filter = 0;
|
||||
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
BakeManager::~BakeManager()
|
||||
@@ -114,9 +114,9 @@ void BakeManager::set(Scene *scene,
|
||||
|
||||
/* create device and update scene */
|
||||
scene->film->tag_modified();
|
||||
scene->integrator->tag_update(scene);
|
||||
scene->integrator->tag_update(scene, Integrator::UPDATE_ALL);
|
||||
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
void BakeManager::device_update(Device * /*device*/,
|
||||
@@ -124,7 +124,7 @@ void BakeManager::device_update(Device * /*device*/,
|
||||
Scene *scene,
|
||||
Progress & /* progress */)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
@@ -152,11 +152,21 @@ void BakeManager::device_update(Device * /*device*/,
|
||||
object_index++;
|
||||
}
|
||||
|
||||
need_update = false;
|
||||
need_update_ = false;
|
||||
}
|
||||
|
||||
void BakeManager::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
|
||||
{
|
||||
}
|
||||
|
||||
void BakeManager::tag_update()
|
||||
{
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
bool BakeManager::need_update() const
|
||||
{
|
||||
return need_update_;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -36,9 +36,12 @@ class BakeManager {
|
||||
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
|
||||
void device_free(Device *device, DeviceScene *dscene);
|
||||
|
||||
bool need_update;
|
||||
void tag_update();
|
||||
|
||||
bool need_update() const;
|
||||
|
||||
private:
|
||||
bool need_update_;
|
||||
ShaderEvalType type;
|
||||
int pass_filter;
|
||||
std::string object_name;
|
||||
|
@@ -688,16 +688,16 @@ void Film::device_free(Device * /*device*/, DeviceScene * /*dscene*/, Scene *sce
|
||||
void Film::tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes)
|
||||
{
|
||||
if (Pass::contains(scene->passes, PASS_UV) != Pass::contains(passes_, PASS_UV)) {
|
||||
scene->geometry_manager->tag_update(scene);
|
||||
scene->geometry_manager->tag_update(scene, GeometryManager::UV_PASS_NEEDED);
|
||||
|
||||
foreach (Shader *shader, scene->shaders)
|
||||
shader->need_update_geometry = true;
|
||||
shader->need_update_uvs = true;
|
||||
}
|
||||
else if (Pass::contains(scene->passes, PASS_MOTION) != Pass::contains(passes_, PASS_MOTION)) {
|
||||
scene->geometry_manager->tag_update(scene);
|
||||
scene->geometry_manager->tag_update(scene, GeometryManager::MOTION_PASS_NEEDED);
|
||||
}
|
||||
else if (Pass::contains(scene->passes, PASS_AO) != Pass::contains(passes_, PASS_AO)) {
|
||||
scene->integrator->tag_update(scene);
|
||||
scene->integrator->tag_update(scene, Integrator::AO_PASS_MODIFIED);
|
||||
}
|
||||
|
||||
if (update_passes) {
|
||||
|
@@ -240,7 +240,6 @@ void Geometry::compute_bvh(
|
||||
}
|
||||
}
|
||||
|
||||
clear_modified();
|
||||
need_update_rebuild = false;
|
||||
}
|
||||
|
||||
@@ -262,22 +261,21 @@ bool Geometry::has_voxel_attributes() const
|
||||
|
||||
void Geometry::tag_update(Scene *scene, bool rebuild)
|
||||
{
|
||||
tag_modified();
|
||||
|
||||
if (rebuild) {
|
||||
need_update_rebuild = true;
|
||||
scene->light_manager->need_update = true;
|
||||
scene->light_manager->tag_update(scene, LightManager::MESH_NEED_REBUILD);
|
||||
}
|
||||
else {
|
||||
foreach (Node *node, used_shaders) {
|
||||
Shader *shader = static_cast<Shader *>(node);
|
||||
if (shader->has_surface_emission)
|
||||
scene->light_manager->need_update = true;
|
||||
if (shader->has_surface_emission) {
|
||||
scene->light_manager->tag_update(scene, LightManager::EMISSIVE_MESH_MODIFIED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scene->geometry_manager->need_update = true;
|
||||
scene->object_manager->need_update = true;
|
||||
scene->geometry_manager->tag_update(scene, GeometryManager::GEOMETRY_MODIFIED);
|
||||
}
|
||||
|
||||
void Geometry::tag_bvh_update(bool rebuild)
|
||||
@@ -293,7 +291,7 @@ void Geometry::tag_bvh_update(bool rebuild)
|
||||
|
||||
GeometryManager::GeometryManager()
|
||||
{
|
||||
need_update = true;
|
||||
update_flags = UPDATE_ALL;
|
||||
need_flags_update = true;
|
||||
}
|
||||
|
||||
@@ -494,6 +492,10 @@ void GeometryManager::update_svm_attributes(Device *,
|
||||
if (attr_map_size == 0)
|
||||
return;
|
||||
|
||||
if (!dscene->attributes_map.need_realloc()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* create attribute map */
|
||||
uint4 *attr_map = dscene->attributes_map.alloc(attr_map_size);
|
||||
memset(attr_map, 0, dscene->attributes_map.size() * sizeof(uint));
|
||||
@@ -602,8 +604,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
|
||||
offset = attr_uchar4_offset;
|
||||
|
||||
assert(attr_uchar4.size() >= offset + size);
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_uchar4[offset + k] = data[k];
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_uchar4[offset + k] = data[k];
|
||||
}
|
||||
}
|
||||
attr_uchar4_offset += size;
|
||||
}
|
||||
@@ -612,8 +616,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
|
||||
offset = attr_float_offset;
|
||||
|
||||
assert(attr_float.size() >= offset + size);
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float[offset + k] = data[k];
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float[offset + k] = data[k];
|
||||
}
|
||||
}
|
||||
attr_float_offset += size;
|
||||
}
|
||||
@@ -622,8 +628,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
|
||||
offset = attr_float2_offset;
|
||||
|
||||
assert(attr_float2.size() >= offset + size);
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float2[offset + k] = data[k];
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float2[offset + k] = data[k];
|
||||
}
|
||||
}
|
||||
attr_float2_offset += size;
|
||||
}
|
||||
@@ -632,8 +640,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
|
||||
offset = attr_float3_offset;
|
||||
|
||||
assert(attr_float3.size() >= offset + size * 3);
|
||||
for (size_t k = 0; k < size * 3; k++) {
|
||||
attr_float3[offset + k] = (&tfm->x)[k];
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size * 3; k++) {
|
||||
attr_float3[offset + k] = (&tfm->x)[k];
|
||||
}
|
||||
}
|
||||
attr_float3_offset += size * 3;
|
||||
}
|
||||
@@ -642,8 +652,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
|
||||
offset = attr_float3_offset;
|
||||
|
||||
assert(attr_float3.size() >= offset + size);
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float3[offset + k] = data[k];
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float3[offset + k] = data[k];
|
||||
}
|
||||
}
|
||||
attr_float3_offset += size;
|
||||
}
|
||||
@@ -808,6 +820,11 @@ void GeometryManager::device_update_attributes(Device *device,
|
||||
dscene->attributes_float3.alloc(attr_float3_size);
|
||||
dscene->attributes_uchar4.alloc(attr_uchar4_size);
|
||||
|
||||
const bool copy_all_data = dscene->attributes_float.need_realloc() ||
|
||||
dscene->attributes_float2.need_realloc() ||
|
||||
dscene->attributes_float3.need_realloc() ||
|
||||
dscene->attributes_uchar4.need_realloc();
|
||||
|
||||
size_t attr_float_offset = 0;
|
||||
size_t attr_float2_offset = 0;
|
||||
size_t attr_float3_offset = 0;
|
||||
@@ -822,6 +839,12 @@ void GeometryManager::device_update_attributes(Device *device,
|
||||
* they actually refer to the same mesh attributes, optimize */
|
||||
foreach (AttributeRequest &req, attributes.requests) {
|
||||
Attribute *attr = geom->attributes.find(req);
|
||||
|
||||
if (attr) {
|
||||
/* force a copy if we need to reallocate all the data */
|
||||
attr->modified |= copy_all_data;
|
||||
}
|
||||
|
||||
update_attribute_element_offset(geom,
|
||||
dscene->attributes_float,
|
||||
attr_float_offset,
|
||||
@@ -840,6 +863,11 @@ void GeometryManager::device_update_attributes(Device *device,
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
Attribute *subd_attr = mesh->subd_attributes.find(req);
|
||||
|
||||
if (subd_attr) {
|
||||
/* force a copy if we need to reallocate all the data */
|
||||
subd_attr->modified |= copy_all_data;
|
||||
}
|
||||
|
||||
update_attribute_element_offset(mesh,
|
||||
dscene->attributes_float,
|
||||
attr_float_offset,
|
||||
@@ -903,18 +931,10 @@ void GeometryManager::device_update_attributes(Device *device,
|
||||
/* copy to device */
|
||||
progress.set_status("Updating Mesh", "Copying Attributes to device");
|
||||
|
||||
if (dscene->attributes_float.size()) {
|
||||
dscene->attributes_float.copy_to_device();
|
||||
}
|
||||
if (dscene->attributes_float2.size()) {
|
||||
dscene->attributes_float2.copy_to_device();
|
||||
}
|
||||
if (dscene->attributes_float3.size()) {
|
||||
dscene->attributes_float3.copy_to_device();
|
||||
}
|
||||
if (dscene->attributes_uchar4.size()) {
|
||||
dscene->attributes_uchar4.copy_to_device();
|
||||
}
|
||||
dscene->attributes_float.copy_to_device();
|
||||
dscene->attributes_float2.copy_to_device();
|
||||
dscene->attributes_float3.copy_to_device();
|
||||
dscene->attributes_uchar4.copy_to_device();
|
||||
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
@@ -1066,17 +1086,34 @@ void GeometryManager::device_update_mesh(
|
||||
uint *tri_patch = dscene->tri_patch.alloc(tri_size);
|
||||
float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size);
|
||||
|
||||
const bool copy_all_data = dscene->tri_shader.need_realloc() ||
|
||||
dscene->tri_vindex.need_realloc() ||
|
||||
dscene->tri_vnormal.need_realloc() ||
|
||||
dscene->tri_patch.need_realloc() ||
|
||||
dscene->tri_patch_uv.need_realloc();
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]);
|
||||
mesh->pack_normals(&vnormal[mesh->vert_offset]);
|
||||
mesh->pack_verts(tri_prim_index,
|
||||
&tri_vindex[mesh->prim_offset],
|
||||
&tri_patch[mesh->prim_offset],
|
||||
&tri_patch_uv[mesh->vert_offset],
|
||||
mesh->vert_offset,
|
||||
mesh->prim_offset);
|
||||
|
||||
if (mesh->shader_is_modified() || mesh->smooth_is_modified() ||
|
||||
mesh->triangles_is_modified() || copy_all_data) {
|
||||
mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]);
|
||||
}
|
||||
|
||||
if (mesh->verts_is_modified() || copy_all_data) {
|
||||
mesh->pack_normals(&vnormal[mesh->vert_offset]);
|
||||
}
|
||||
|
||||
if (mesh->triangles_is_modified() || mesh->vert_patch_uv_is_modified() || copy_all_data) {
|
||||
mesh->pack_verts(tri_prim_index,
|
||||
&tri_vindex[mesh->prim_offset],
|
||||
&tri_patch[mesh->prim_offset],
|
||||
&tri_patch_uv[mesh->vert_offset],
|
||||
mesh->vert_offset,
|
||||
mesh->prim_offset);
|
||||
}
|
||||
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
}
|
||||
@@ -1085,11 +1122,11 @@ void GeometryManager::device_update_mesh(
|
||||
/* vertex coordinates */
|
||||
progress.set_status("Updating Mesh", "Copying Mesh to device");
|
||||
|
||||
dscene->tri_shader.copy_to_device();
|
||||
dscene->tri_vnormal.copy_to_device();
|
||||
dscene->tri_vindex.copy_to_device();
|
||||
dscene->tri_patch.copy_to_device();
|
||||
dscene->tri_patch_uv.copy_to_device();
|
||||
dscene->tri_shader.copy_to_device_if_modified();
|
||||
dscene->tri_vnormal.copy_to_device_if_modified();
|
||||
dscene->tri_vindex.copy_to_device_if_modified();
|
||||
dscene->tri_patch.copy_to_device_if_modified();
|
||||
dscene->tri_patch_uv.copy_to_device_if_modified();
|
||||
}
|
||||
|
||||
if (curve_size != 0) {
|
||||
@@ -1098,9 +1135,21 @@ void GeometryManager::device_update_mesh(
|
||||
float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size);
|
||||
float4 *curves = dscene->curves.alloc(curve_size);
|
||||
|
||||
const bool copy_all_data = dscene->curve_keys.need_realloc() || dscene->curves.need_realloc();
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
if (geom->is_hair()) {
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
|
||||
bool curve_keys_co_modified = hair->curve_radius_is_modified() ||
|
||||
hair->curve_keys_is_modified();
|
||||
bool curve_data_modified = hair->curve_shader_is_modified() ||
|
||||
hair->curve_first_key_is_modified();
|
||||
|
||||
if (!curve_keys_co_modified && !curve_data_modified && !copy_all_data) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hair->pack_curves(scene,
|
||||
&curve_keys[hair->curvekey_offset],
|
||||
&curves[hair->prim_offset],
|
||||
@@ -1110,11 +1159,11 @@ void GeometryManager::device_update_mesh(
|
||||
}
|
||||
}
|
||||
|
||||
dscene->curve_keys.copy_to_device();
|
||||
dscene->curves.copy_to_device();
|
||||
dscene->curve_keys.copy_to_device_if_modified();
|
||||
dscene->curves.copy_to_device_if_modified();
|
||||
}
|
||||
|
||||
if (patch_size != 0) {
|
||||
if (patch_size != 0 && dscene->patches.need_realloc()) {
|
||||
progress.set_status("Updating Mesh", "Copying Patches to device");
|
||||
|
||||
uint *patch_data = dscene->patches.alloc(patch_size);
|
||||
@@ -1180,16 +1229,25 @@ void GeometryManager::device_update_bvh(Device *device,
|
||||
|
||||
VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout.";
|
||||
|
||||
delete scene->bvh;
|
||||
BVH *bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device);
|
||||
device->build_bvh(bvh, progress, false);
|
||||
const bool can_refit = scene->bvh != nullptr &&
|
||||
(bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX);
|
||||
const bool pack_all = scene->bvh == nullptr;
|
||||
|
||||
BVH *bvh = scene->bvh;
|
||||
if (!scene->bvh) {
|
||||
bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device);
|
||||
}
|
||||
|
||||
device->build_bvh(bvh, progress, can_refit);
|
||||
|
||||
if (progress.get_cancel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool has_bvh2_layout = (bparams.bvh_layout == BVH_LAYOUT_BVH2);
|
||||
|
||||
PackedBVH pack;
|
||||
if (bparams.bvh_layout == BVH_LAYOUT_BVH2) {
|
||||
if (has_bvh2_layout) {
|
||||
pack = std::move(static_cast<BVH2 *>(bvh)->pack);
|
||||
}
|
||||
else {
|
||||
@@ -1210,12 +1268,22 @@ void GeometryManager::device_update_bvh(Device *device,
|
||||
}
|
||||
|
||||
pack.root_index = -1;
|
||||
pack.prim_tri_index.reserve(num_prims);
|
||||
pack.prim_tri_verts.reserve(num_tri_verts);
|
||||
pack.prim_type.reserve(num_prims);
|
||||
pack.prim_index.reserve(num_prims);
|
||||
pack.prim_object.reserve(num_prims);
|
||||
pack.prim_visibility.reserve(num_prims);
|
||||
|
||||
if (!pack_all) {
|
||||
/* if we do not need to recreate the BVH, then only the vertices are updated, so we can
|
||||
* safely retake the memory */
|
||||
dscene->prim_tri_verts.give_data(pack.prim_tri_verts);
|
||||
}
|
||||
else {
|
||||
/* It is not strictly necessary to skip those resizes we if do not have to repack, as the OS
|
||||
* will not allocate pages if we do not touch them, however it does help catching bugs. */
|
||||
pack.prim_tri_index.resize(num_prims);
|
||||
pack.prim_tri_verts.resize(num_tri_verts);
|
||||
pack.prim_type.resize(num_prims);
|
||||
pack.prim_index.resize(num_prims);
|
||||
pack.prim_object.resize(num_prims);
|
||||
pack.prim_visibility.resize(num_prims);
|
||||
}
|
||||
|
||||
// Merge visibility flags of all objects and find object index for non-instanced geometry
|
||||
unordered_map<const Geometry *, pair<int, uint>> geometry_to_object_info;
|
||||
@@ -1229,17 +1297,27 @@ void GeometryManager::device_update_bvh(Device *device,
|
||||
}
|
||||
}
|
||||
|
||||
TaskPool pool;
|
||||
// Iterate over scene mesh list instead of objects, since 'optix_prim_offset' was calculated
|
||||
// based on that list, which may be ordered differently from the object list.
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
if (!pack_all && !geom->is_modified()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const pair<int, uint> &info = geometry_to_object_info[geom];
|
||||
geom->pack_primitives(pack, info.first, info.second);
|
||||
pool.push(function_bind(
|
||||
&Geometry::pack_primitives, geom, &pack, info.first, info.second, pack_all));
|
||||
}
|
||||
pool.wait_work();
|
||||
}
|
||||
|
||||
/* copy to device */
|
||||
progress.set_status("Updating Scene BVH", "Copying BVH to device");
|
||||
|
||||
/* When using BVH2, we always have to copy/update the data as its layout is dependent on the
|
||||
* BVH's leaf nodes which may be different when the objects or vertices move. */
|
||||
|
||||
if (pack.nodes.size()) {
|
||||
dscene->bvh_nodes.steal_data(pack.nodes);
|
||||
dscene->bvh_nodes.copy_to_device();
|
||||
@@ -1252,7 +1330,7 @@ void GeometryManager::device_update_bvh(Device *device,
|
||||
dscene->object_node.steal_data(pack.object_node);
|
||||
dscene->object_node.copy_to_device();
|
||||
}
|
||||
if (pack.prim_tri_index.size()) {
|
||||
if (pack.prim_tri_index.size() && (dscene->prim_tri_index.need_realloc() || has_bvh2_layout)) {
|
||||
dscene->prim_tri_index.steal_data(pack.prim_tri_index);
|
||||
dscene->prim_tri_index.copy_to_device();
|
||||
}
|
||||
@@ -1260,23 +1338,23 @@ void GeometryManager::device_update_bvh(Device *device,
|
||||
dscene->prim_tri_verts.steal_data(pack.prim_tri_verts);
|
||||
dscene->prim_tri_verts.copy_to_device();
|
||||
}
|
||||
if (pack.prim_type.size()) {
|
||||
if (pack.prim_type.size() && (dscene->prim_type.need_realloc() || has_bvh2_layout)) {
|
||||
dscene->prim_type.steal_data(pack.prim_type);
|
||||
dscene->prim_type.copy_to_device();
|
||||
}
|
||||
if (pack.prim_visibility.size()) {
|
||||
if (pack.prim_visibility.size() && (dscene->prim_visibility.need_realloc() || has_bvh2_layout)) {
|
||||
dscene->prim_visibility.steal_data(pack.prim_visibility);
|
||||
dscene->prim_visibility.copy_to_device();
|
||||
}
|
||||
if (pack.prim_index.size()) {
|
||||
if (pack.prim_index.size() && (dscene->prim_index.need_realloc() || has_bvh2_layout)) {
|
||||
dscene->prim_index.steal_data(pack.prim_index);
|
||||
dscene->prim_index.copy_to_device();
|
||||
}
|
||||
if (pack.prim_object.size()) {
|
||||
if (pack.prim_object.size() && (dscene->prim_object.need_realloc() || has_bvh2_layout)) {
|
||||
dscene->prim_object.steal_data(pack.prim_object);
|
||||
dscene->prim_object.copy_to_device();
|
||||
}
|
||||
if (pack.prim_time.size()) {
|
||||
if (pack.prim_time.size() && (dscene->prim_time.need_realloc() || has_bvh2_layout)) {
|
||||
dscene->prim_time.steal_data(pack.prim_time);
|
||||
dscene->prim_time.copy_to_device();
|
||||
}
|
||||
@@ -1289,12 +1367,65 @@ void GeometryManager::device_update_bvh(Device *device,
|
||||
dscene->data.bvh.scene = NULL;
|
||||
}
|
||||
|
||||
/* Set of flags used to help determining what data has been modified or needs reallocation, so we
|
||||
* can decide which device data to free or update. */
|
||||
enum {
|
||||
DEVICE_CURVE_DATA_MODIFIED = (1 << 0),
|
||||
DEVICE_MESH_DATA_MODIFIED = (1 << 1),
|
||||
|
||||
ATTR_FLOAT_MODIFIED = (1 << 2),
|
||||
ATTR_FLOAT2_MODIFIED = (1 << 3),
|
||||
ATTR_FLOAT3_MODIFIED = (1 << 4),
|
||||
ATTR_UCHAR4_MODIFIED = (1 << 5),
|
||||
|
||||
CURVE_DATA_NEED_REALLOC = (1 << 6),
|
||||
MESH_DATA_NEED_REALLOC = (1 << 7),
|
||||
|
||||
ATTR_FLOAT_NEEDS_REALLOC = (1 << 8),
|
||||
ATTR_FLOAT2_NEEDS_REALLOC = (1 << 9),
|
||||
ATTR_FLOAT3_NEEDS_REALLOC = (1 << 10),
|
||||
ATTR_UCHAR4_NEEDS_REALLOC = (1 << 11),
|
||||
|
||||
ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC |
|
||||
ATTR_FLOAT3_NEEDS_REALLOC | ATTR_UCHAR4_NEEDS_REALLOC),
|
||||
DEVICE_MESH_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
|
||||
DEVICE_CURVE_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
|
||||
};
|
||||
|
||||
static void update_device_flags_attribute(uint32_t &device_update_flags,
|
||||
const AttributeSet &attributes)
|
||||
{
|
||||
foreach (const Attribute &attr, attributes.attributes) {
|
||||
if (!attr.modified) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (attr.element == ATTR_ELEMENT_CORNER) {
|
||||
device_update_flags |= ATTR_UCHAR4_MODIFIED;
|
||||
}
|
||||
else if (attr.type == TypeDesc::TypeFloat) {
|
||||
device_update_flags |= ATTR_FLOAT_MODIFIED;
|
||||
}
|
||||
else if (attr.type == TypeFloat2) {
|
||||
device_update_flags |= ATTR_FLOAT2_MODIFIED;
|
||||
}
|
||||
else if (attr.type == TypeDesc::TypeMatrix) {
|
||||
device_update_flags |= ATTR_FLOAT3_MODIFIED;
|
||||
}
|
||||
else if (attr.element != ATTR_ELEMENT_VOXEL) {
|
||||
device_update_flags |= ATTR_FLOAT3_MODIFIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Progress &progress)
|
||||
{
|
||||
if (!need_update && !need_flags_update) {
|
||||
if (!need_update() && !need_flags_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t device_update_flags = 0;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
if (scene->update_stats) {
|
||||
scene->update_stats->geometry.times.add_entry({"device_update_preprocess", time});
|
||||
@@ -1314,9 +1445,54 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
|
||||
if (shader->has_volume) {
|
||||
geom->has_volume = true;
|
||||
}
|
||||
|
||||
if (shader->has_surface_bssrdf) {
|
||||
geom->has_surface_bssrdf = true;
|
||||
}
|
||||
|
||||
if (shader->need_update_uvs) {
|
||||
device_update_flags |= ATTR_FLOAT2_NEEDS_REALLOC;
|
||||
|
||||
/* Attributes might need to be tesselated if added. */
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
if (mesh->need_tesselation()) {
|
||||
mesh->tag_modified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shader->need_update_attribute) {
|
||||
device_update_flags |= ATTRS_NEED_REALLOC;
|
||||
|
||||
/* Attributes might need to be tesselated if added. */
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
if (mesh->need_tesselation()) {
|
||||
mesh->tag_modified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shader->need_update_displacement) {
|
||||
/* tag displacement related sockets as modified */
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
mesh->tag_verts_modified();
|
||||
mesh->tag_subd_dicing_rate_modified();
|
||||
mesh->tag_subd_max_level_modified();
|
||||
mesh->tag_subd_objecttoworld_modified();
|
||||
|
||||
device_update_flags |= ATTRS_NEED_REALLOC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* only check for modified attributes if we do not need to reallocate them already */
|
||||
if ((device_update_flags & ATTRS_NEED_REALLOC) == 0) {
|
||||
update_device_flags_attribute(device_update_flags, geom->attributes);
|
||||
/* don't check for subd_attributes, as if they were modified, we would need to reallocate
|
||||
* anyway */
|
||||
}
|
||||
|
||||
/* Re-create volume mesh if we will rebuild or refit the BVH. Note we
|
||||
@@ -1332,13 +1508,119 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
|
||||
|
||||
Volume *volume = static_cast<Volume *>(geom);
|
||||
create_volume_mesh(volume, progress);
|
||||
|
||||
/* always reallocate when we have a volume, as we need to rebuild the BVH */
|
||||
device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
|
||||
}
|
||||
|
||||
if (geom->is_hair()) {
|
||||
/* Set curve shape, still a global scene setting for now. */
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
hair->curve_shape = scene->params.hair_shape;
|
||||
|
||||
if (hair->need_update_rebuild) {
|
||||
device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC;
|
||||
}
|
||||
else if (hair->is_modified()) {
|
||||
device_update_flags |= DEVICE_CURVE_DATA_MODIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
|
||||
if (mesh->need_update_rebuild) {
|
||||
device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
|
||||
}
|
||||
else if (mesh->is_modified()) {
|
||||
device_update_flags |= DEVICE_MESH_DATA_MODIFIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (update_flags & (MESH_ADDED | MESH_REMOVED)) {
|
||||
device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
|
||||
}
|
||||
|
||||
if (update_flags & (HAIR_ADDED | HAIR_REMOVED)) {
|
||||
device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC;
|
||||
}
|
||||
|
||||
/* tag the device arrays for reallocation or modification */
|
||||
DeviceScene *dscene = &scene->dscene;
|
||||
|
||||
if (device_update_flags & (DEVICE_MESH_DATA_NEEDS_REALLOC | DEVICE_CURVE_DATA_NEEDS_REALLOC)) {
|
||||
delete scene->bvh;
|
||||
scene->bvh = nullptr;
|
||||
|
||||
dscene->bvh_nodes.tag_realloc();
|
||||
dscene->bvh_leaf_nodes.tag_realloc();
|
||||
dscene->object_node.tag_realloc();
|
||||
dscene->prim_tri_verts.tag_realloc();
|
||||
dscene->prim_tri_index.tag_realloc();
|
||||
dscene->prim_type.tag_realloc();
|
||||
dscene->prim_visibility.tag_realloc();
|
||||
dscene->prim_index.tag_realloc();
|
||||
dscene->prim_object.tag_realloc();
|
||||
dscene->prim_time.tag_realloc();
|
||||
|
||||
if (device_update_flags & DEVICE_MESH_DATA_NEEDS_REALLOC) {
|
||||
dscene->tri_vnormal.tag_realloc();
|
||||
dscene->tri_vindex.tag_realloc();
|
||||
dscene->tri_patch.tag_realloc();
|
||||
dscene->tri_vnormal.tag_realloc();
|
||||
dscene->tri_patch_uv.tag_realloc();
|
||||
dscene->patches.tag_realloc();
|
||||
}
|
||||
|
||||
if (device_update_flags & DEVICE_CURVE_DATA_NEEDS_REALLOC) {
|
||||
dscene->curves.tag_realloc();
|
||||
dscene->curve_keys.tag_realloc();
|
||||
}
|
||||
}
|
||||
|
||||
if (device_update_flags & ATTR_FLOAT_NEEDS_REALLOC) {
|
||||
dscene->attributes_map.tag_realloc();
|
||||
dscene->attributes_float.tag_realloc();
|
||||
}
|
||||
else if (device_update_flags & ATTR_FLOAT_MODIFIED) {
|
||||
dscene->attributes_float.tag_modified();
|
||||
}
|
||||
|
||||
if (device_update_flags & ATTR_FLOAT2_NEEDS_REALLOC) {
|
||||
dscene->attributes_map.tag_realloc();
|
||||
dscene->attributes_float2.tag_realloc();
|
||||
}
|
||||
else if (device_update_flags & ATTR_FLOAT_MODIFIED) {
|
||||
dscene->attributes_float.tag_modified();
|
||||
}
|
||||
|
||||
if (device_update_flags & ATTR_FLOAT3_NEEDS_REALLOC) {
|
||||
dscene->attributes_map.tag_realloc();
|
||||
dscene->attributes_float3.tag_realloc();
|
||||
}
|
||||
else if (device_update_flags & ATTR_FLOAT_MODIFIED) {
|
||||
dscene->attributes_float.tag_modified();
|
||||
}
|
||||
|
||||
if (device_update_flags & ATTR_UCHAR4_NEEDS_REALLOC) {
|
||||
dscene->attributes_map.tag_realloc();
|
||||
dscene->attributes_uchar4.tag_realloc();
|
||||
}
|
||||
else if (device_update_flags & ATTR_UCHAR4_MODIFIED) {
|
||||
dscene->attributes_uchar4.tag_modified();
|
||||
}
|
||||
|
||||
if (device_update_flags & DEVICE_MESH_DATA_MODIFIED) {
|
||||
/* if anything else than vertices or shaders are modified, we would need to reallocate, so
|
||||
* these are the only arrays that can be updated */
|
||||
dscene->tri_vnormal.tag_modified();
|
||||
dscene->tri_shader.tag_modified();
|
||||
}
|
||||
|
||||
if (device_update_flags & DEVICE_CURVE_DATA_MODIFIED) {
|
||||
dscene->curve_keys.tag_modified();
|
||||
dscene->curves.tag_modified();
|
||||
}
|
||||
|
||||
need_flags_update = false;
|
||||
@@ -1423,7 +1705,7 @@ void GeometryManager::device_update(Device *device,
|
||||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
VLOG(1) << "Total " << scene->geometry.size() << " meshes.";
|
||||
@@ -1439,12 +1721,6 @@ void GeometryManager::device_update(Device *device,
|
||||
});
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
foreach (Node *node, geom->get_used_shaders()) {
|
||||
Shader *shader = static_cast<Shader *>(node);
|
||||
if (shader->need_update_geometry)
|
||||
geom->tag_modified();
|
||||
}
|
||||
|
||||
if (geom->is_modified() &&
|
||||
(geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME)) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
@@ -1541,7 +1817,7 @@ void GeometryManager::device_update(Device *device,
|
||||
}
|
||||
|
||||
/* Device update. */
|
||||
device_free(device, dscene);
|
||||
device_free(device, dscene, false);
|
||||
|
||||
const BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout,
|
||||
device->get_bvh_layout_mask());
|
||||
@@ -1614,7 +1890,7 @@ void GeometryManager::device_update(Device *device,
|
||||
{"device_update (displacement: attributes)", time});
|
||||
}
|
||||
});
|
||||
device_free(device, dscene);
|
||||
device_free(device, dscene, false);
|
||||
|
||||
device_update_attributes(device, dscene, scene, progress);
|
||||
if (progress.get_cancel()) {
|
||||
@@ -1622,6 +1898,9 @@ void GeometryManager::device_update(Device *device,
|
||||
}
|
||||
}
|
||||
|
||||
/* update the bvh even when there is no geometry so the kernel bvh data is still valid,
|
||||
* especially when removing all of the objects during interactive renders */
|
||||
bool need_update_scene_bvh = (scene->bvh == nullptr);
|
||||
{
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
if (scene->update_stats) {
|
||||
@@ -1633,6 +1912,7 @@ void GeometryManager::device_update(Device *device,
|
||||
size_t i = 0;
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
if (geom->is_modified()) {
|
||||
need_update_scene_bvh = true;
|
||||
pool.push(function_bind(
|
||||
&Geometry::compute_bvh, geom, device, dscene, &scene->params, &progress, i, num_bvh));
|
||||
if (geom->need_build_bvh(bvh_layout)) {
|
||||
@@ -1647,7 +1927,9 @@ void GeometryManager::device_update(Device *device,
|
||||
}
|
||||
|
||||
foreach (Shader *shader, scene->shaders) {
|
||||
shader->need_update_geometry = false;
|
||||
shader->need_update_uvs = false;
|
||||
shader->need_update_attribute = false;
|
||||
shader->need_update_displacement = false;
|
||||
}
|
||||
|
||||
Scene::MotionType need_motion = scene->need_motion();
|
||||
@@ -1670,7 +1952,7 @@ void GeometryManager::device_update(Device *device,
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
if (need_update_scene_bvh) {
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
if (scene->update_stats) {
|
||||
scene->update_stats->geometry.times.add_entry({"device_update (build scene BVH)", time});
|
||||
@@ -1695,8 +1977,6 @@ void GeometryManager::device_update(Device *device,
|
||||
}
|
||||
}
|
||||
|
||||
need_update = false;
|
||||
|
||||
if (true_displacement_used) {
|
||||
/* Re-tag flags for update, so they're re-evaluated
|
||||
* for meshes with correct bounding boxes.
|
||||
@@ -1706,33 +1986,71 @@ void GeometryManager::device_update(Device *device,
|
||||
*/
|
||||
scene->object_manager->need_flags_update = old_need_object_flags_update;
|
||||
}
|
||||
|
||||
/* unset flags */
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
geom->clear_modified();
|
||||
geom->attributes.clear_modified();
|
||||
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
mesh->subd_attributes.clear_modified();
|
||||
}
|
||||
}
|
||||
|
||||
update_flags = UPDATE_NONE;
|
||||
|
||||
dscene->bvh_nodes.clear_modified();
|
||||
dscene->bvh_leaf_nodes.clear_modified();
|
||||
dscene->object_node.clear_modified();
|
||||
dscene->prim_tri_verts.clear_modified();
|
||||
dscene->prim_tri_index.clear_modified();
|
||||
dscene->prim_type.clear_modified();
|
||||
dscene->prim_visibility.clear_modified();
|
||||
dscene->prim_index.clear_modified();
|
||||
dscene->prim_object.clear_modified();
|
||||
dscene->prim_time.clear_modified();
|
||||
dscene->tri_shader.clear_modified();
|
||||
dscene->tri_vindex.clear_modified();
|
||||
dscene->tri_patch.clear_modified();
|
||||
dscene->tri_vnormal.clear_modified();
|
||||
dscene->tri_patch_uv.clear_modified();
|
||||
dscene->curves.clear_modified();
|
||||
dscene->curve_keys.clear_modified();
|
||||
dscene->patches.clear_modified();
|
||||
dscene->attributes_map.clear_modified();
|
||||
dscene->attributes_float.clear_modified();
|
||||
dscene->attributes_float2.clear_modified();
|
||||
dscene->attributes_float3.clear_modified();
|
||||
dscene->attributes_uchar4.clear_modified();
|
||||
}
|
||||
|
||||
void GeometryManager::device_free(Device *device, DeviceScene *dscene)
|
||||
void GeometryManager::device_free(Device *device, DeviceScene *dscene, bool force_free)
|
||||
{
|
||||
dscene->bvh_nodes.free();
|
||||
dscene->bvh_leaf_nodes.free();
|
||||
dscene->object_node.free();
|
||||
dscene->prim_tri_verts.free();
|
||||
dscene->prim_tri_index.free();
|
||||
dscene->prim_type.free();
|
||||
dscene->prim_visibility.free();
|
||||
dscene->prim_index.free();
|
||||
dscene->prim_object.free();
|
||||
dscene->prim_time.free();
|
||||
dscene->tri_shader.free();
|
||||
dscene->tri_vnormal.free();
|
||||
dscene->tri_vindex.free();
|
||||
dscene->tri_patch.free();
|
||||
dscene->tri_patch_uv.free();
|
||||
dscene->curves.free();
|
||||
dscene->curve_keys.free();
|
||||
dscene->patches.free();
|
||||
dscene->attributes_map.free();
|
||||
dscene->attributes_float.free();
|
||||
dscene->attributes_float2.free();
|
||||
dscene->attributes_float3.free();
|
||||
dscene->attributes_uchar4.free();
|
||||
dscene->bvh_nodes.free_if_need_realloc(force_free);
|
||||
dscene->bvh_leaf_nodes.free_if_need_realloc(force_free);
|
||||
dscene->object_node.free_if_need_realloc(force_free);
|
||||
dscene->prim_tri_verts.free_if_need_realloc(force_free);
|
||||
dscene->prim_tri_index.free_if_need_realloc(force_free);
|
||||
dscene->prim_type.free_if_need_realloc(force_free);
|
||||
dscene->prim_visibility.free_if_need_realloc(force_free);
|
||||
dscene->prim_index.free_if_need_realloc(force_free);
|
||||
dscene->prim_object.free_if_need_realloc(force_free);
|
||||
dscene->prim_time.free_if_need_realloc(force_free);
|
||||
dscene->tri_shader.free_if_need_realloc(force_free);
|
||||
dscene->tri_vnormal.free_if_need_realloc(force_free);
|
||||
dscene->tri_vindex.free_if_need_realloc(force_free);
|
||||
dscene->tri_patch.free_if_need_realloc(force_free);
|
||||
dscene->tri_patch_uv.free_if_need_realloc(force_free);
|
||||
dscene->curves.free_if_need_realloc(force_free);
|
||||
dscene->curve_keys.free_if_need_realloc(force_free);
|
||||
dscene->patches.free_if_need_realloc(force_free);
|
||||
dscene->attributes_map.free_if_need_realloc(force_free);
|
||||
dscene->attributes_float.free_if_need_realloc(force_free);
|
||||
dscene->attributes_float2.free_if_need_realloc(force_free);
|
||||
dscene->attributes_float3.free_if_need_realloc(force_free);
|
||||
dscene->attributes_uchar4.free_if_need_realloc(force_free);
|
||||
|
||||
/* Signal for shaders like displacement not to do ray tracing. */
|
||||
dscene->data.bvh.bvh_layout = BVH_LAYOUT_NONE;
|
||||
@@ -1750,10 +2068,19 @@ void GeometryManager::device_free(Device *device, DeviceScene *dscene)
|
||||
#endif
|
||||
}
|
||||
|
||||
void GeometryManager::tag_update(Scene *scene)
|
||||
void GeometryManager::tag_update(Scene *scene, uint32_t flag)
|
||||
{
|
||||
need_update = true;
|
||||
scene->object_manager->need_update = true;
|
||||
update_flags |= flag;
|
||||
|
||||
/* do not tag the object manager for an update if it is the one who tagged us */
|
||||
if ((flag & OBJECT_MANAGER) == 0) {
|
||||
scene->object_manager->tag_update(scene, ObjectManager::GEOMETRY_MANAGER);
|
||||
}
|
||||
}
|
||||
|
||||
bool GeometryManager::need_update() const
|
||||
{
|
||||
return update_flags != UPDATE_NONE;
|
||||
}
|
||||
|
||||
void GeometryManager::collect_statistics(const Scene *scene, RenderStats *stats)
|
||||
|
@@ -125,7 +125,7 @@ class Geometry : public Node {
|
||||
int n,
|
||||
int total);
|
||||
|
||||
virtual void pack_primitives(PackedBVH &pack, int object, uint visibility) = 0;
|
||||
virtual void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) = 0;
|
||||
|
||||
/* Check whether the geometry should have own BVH built separately. Briefly,
|
||||
* own BVH is needed for geometry, if:
|
||||
@@ -155,6 +155,11 @@ class Geometry : public Node {
|
||||
return geometry_type == HAIR;
|
||||
}
|
||||
|
||||
bool is_volume() const
|
||||
{
|
||||
return geometry_type == VOLUME;
|
||||
}
|
||||
|
||||
/* Updates */
|
||||
void tag_update(Scene *scene, bool rebuild);
|
||||
|
||||
@@ -164,9 +169,32 @@ class Geometry : public Node {
|
||||
/* Geometry Manager */
|
||||
|
||||
class GeometryManager {
|
||||
uint32_t update_flags;
|
||||
|
||||
public:
|
||||
enum : uint32_t {
|
||||
UV_PASS_NEEDED = (1 << 0),
|
||||
MOTION_PASS_NEEDED = (1 << 1),
|
||||
GEOMETRY_MODIFIED = (1 << 2),
|
||||
OBJECT_MANAGER = (1 << 3),
|
||||
MESH_ADDED = (1 << 4),
|
||||
MESH_REMOVED = (1 << 5),
|
||||
HAIR_ADDED = (1 << 6),
|
||||
HAIR_REMOVED = (1 << 7),
|
||||
|
||||
SHADER_ATTRIBUTE_MODIFIED = (1 << 8),
|
||||
SHADER_DISPLACEMENT_MODIFIED = (1 << 9),
|
||||
|
||||
GEOMETRY_ADDED = MESH_ADDED | HAIR_ADDED,
|
||||
GEOMETRY_REMOVED = MESH_REMOVED | HAIR_REMOVED,
|
||||
|
||||
/* tag everything in the manager for an update */
|
||||
UPDATE_ALL = ~0u,
|
||||
|
||||
UPDATE_NONE = 0u,
|
||||
};
|
||||
|
||||
/* Update Flags */
|
||||
bool need_update;
|
||||
bool need_flags_update;
|
||||
|
||||
/* Constructor/Destructor */
|
||||
@@ -176,10 +204,12 @@ class GeometryManager {
|
||||
/* Device Updates */
|
||||
void device_update_preprocess(Device *device, Scene *scene, Progress &progress);
|
||||
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
|
||||
void device_free(Device *device, DeviceScene *dscene);
|
||||
void device_free(Device *device, DeviceScene *dscene, bool force_free);
|
||||
|
||||
/* Updates */
|
||||
void tag_update(Scene *scene);
|
||||
void tag_update(Scene *scene, uint32_t flag);
|
||||
|
||||
bool need_update() const;
|
||||
|
||||
/* Statistics */
|
||||
void collect_statistics(const Scene *scene, RenderStats *stats);
|
||||
|
@@ -494,33 +494,38 @@ void Hair::pack_curves(Scene *scene,
|
||||
}
|
||||
}
|
||||
|
||||
void Hair::pack_primitives(PackedBVH &pack, int object, uint visibility)
|
||||
void Hair::pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all)
|
||||
{
|
||||
if (curve_first_key.empty())
|
||||
return;
|
||||
|
||||
const size_t num_prims = num_segments();
|
||||
pack.prim_tri_index.reserve(pack.prim_tri_index.size() + num_prims);
|
||||
pack.prim_type.reserve(pack.prim_type.size() + num_prims);
|
||||
pack.prim_visibility.reserve(pack.prim_visibility.size() + num_prims);
|
||||
pack.prim_index.reserve(pack.prim_index.size() + num_prims);
|
||||
pack.prim_object.reserve(pack.prim_object.size() + num_prims);
|
||||
// 'pack.prim_time' is unused by Embree and OptiX
|
||||
/* If the BVH does not have to be recreated, we can bail out. */
|
||||
if (!pack_all) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int *prim_tri_index = &pack->prim_tri_index[optix_prim_offset];
|
||||
int *prim_type = &pack->prim_type[optix_prim_offset];
|
||||
unsigned int *prim_visibility = &pack->prim_visibility[optix_prim_offset];
|
||||
int *prim_index = &pack->prim_index[optix_prim_offset];
|
||||
int *prim_object = &pack->prim_object[optix_prim_offset];
|
||||
// 'pack->prim_time' is unused by Embree and OptiX
|
||||
|
||||
uint type = has_motion_blur() ?
|
||||
((curve_shape == CURVE_RIBBON) ? PRIMITIVE_MOTION_CURVE_RIBBON :
|
||||
PRIMITIVE_MOTION_CURVE_THICK) :
|
||||
((curve_shape == CURVE_RIBBON) ? PRIMITIVE_CURVE_RIBBON : PRIMITIVE_CURVE_THICK);
|
||||
|
||||
size_t index = 0;
|
||||
for (size_t j = 0; j < num_curves(); ++j) {
|
||||
Curve curve = get_curve(j);
|
||||
for (size_t k = 0; k < curve.num_segments(); ++k) {
|
||||
pack.prim_tri_index.push_back_reserved(-1);
|
||||
pack.prim_type.push_back_reserved(PRIMITIVE_PACK_SEGMENT(type, k));
|
||||
pack.prim_visibility.push_back_reserved(visibility);
|
||||
for (size_t k = 0; k < curve.num_segments(); ++k, ++index) {
|
||||
prim_tri_index[index] = -1;
|
||||
prim_type[index] = PRIMITIVE_PACK_SEGMENT(type, k);
|
||||
prim_visibility[index] = visibility;
|
||||
// Each curve segment points back to its curve index
|
||||
pack.prim_index.push_back_reserved(j + prim_offset);
|
||||
pack.prim_object.push_back_reserved(object);
|
||||
prim_index[index] = j + prim_offset;
|
||||
prim_object[index] = object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -146,7 +146,7 @@ class Hair : public Geometry {
|
||||
/* BVH */
|
||||
void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset);
|
||||
|
||||
void pack_primitives(PackedBVH &pack, int object, uint visibility) override;
|
||||
void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) override;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -298,7 +298,7 @@ bool ImageLoader::is_vdb_loader() const
|
||||
|
||||
ImageManager::ImageManager(const DeviceInfo &info)
|
||||
{
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
osl_texture_system = NULL;
|
||||
animation_frame = 0;
|
||||
|
||||
@@ -451,7 +451,7 @@ int ImageManager::add_image_slot(ImageLoader *loader,
|
||||
|
||||
images[slot] = img;
|
||||
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
|
||||
return slot;
|
||||
}
|
||||
@@ -478,7 +478,7 @@ void ImageManager::remove_image_user(int slot)
|
||||
* the reasons for this is that on shader changes we add and remove nodes
|
||||
* that use them, but we do not want to reload the image all the time. */
|
||||
if (image->users == 0)
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
static bool image_associate_alpha(ImageManager::Image *img)
|
||||
@@ -810,7 +810,7 @@ void ImageManager::device_free_image(Device *, int slot)
|
||||
|
||||
void ImageManager::device_update(Device *device, Scene *scene, Progress &progress)
|
||||
{
|
||||
if (!need_update) {
|
||||
if (!need_update()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -834,7 +834,7 @@ void ImageManager::device_update(Device *device, Scene *scene, Progress &progres
|
||||
|
||||
pool.wait_work();
|
||||
|
||||
need_update = false;
|
||||
need_update_ = false;
|
||||
}
|
||||
|
||||
void ImageManager::device_update_slot(Device *device, Scene *scene, int slot, Progress *progress)
|
||||
@@ -854,7 +854,7 @@ void ImageManager::device_load_builtin(Device *device, Scene *scene, Progress &p
|
||||
{
|
||||
/* Load only builtin images, Blender needs this to load evaluated
|
||||
* scene data from depsgraph before it is freed. */
|
||||
if (!need_update) {
|
||||
if (!need_update()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -896,4 +896,14 @@ void ImageManager::collect_statistics(RenderStats *stats)
|
||||
}
|
||||
}
|
||||
|
||||
void ImageManager::tag_update()
|
||||
{
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
bool ImageManager::need_update() const
|
||||
{
|
||||
return need_update_;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -189,7 +189,9 @@ class ImageManager {
|
||||
|
||||
void collect_statistics(RenderStats *stats);
|
||||
|
||||
bool need_update;
|
||||
void tag_update();
|
||||
|
||||
bool need_update() const;
|
||||
|
||||
struct Image {
|
||||
ImageParams params;
|
||||
@@ -209,6 +211,7 @@ class ImageManager {
|
||||
};
|
||||
|
||||
private:
|
||||
bool need_update_;
|
||||
bool has_half_images;
|
||||
|
||||
thread_mutex device_mutex;
|
||||
|
@@ -17,9 +17,11 @@
|
||||
#include "render/integrator.h"
|
||||
#include "device/device.h"
|
||||
#include "render/background.h"
|
||||
#include "render/camera.h"
|
||||
#include "render/film.h"
|
||||
#include "render/jitter.h"
|
||||
#include "render/light.h"
|
||||
#include "render/object.h"
|
||||
#include "render/scene.h"
|
||||
#include "render/shader.h"
|
||||
#include "render/sobol.h"
|
||||
@@ -113,6 +115,10 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
|
||||
}
|
||||
});
|
||||
|
||||
if (sampling_pattern_is_modified()) {
|
||||
dscene->sample_pattern_lut.tag_realloc();
|
||||
}
|
||||
|
||||
device_free(device, dscene);
|
||||
|
||||
KernelIntegrator *kintegrator = &dscene->data.integrator;
|
||||
@@ -168,7 +174,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
|
||||
FLT_MAX :
|
||||
sample_clamp_indirect * 3.0f;
|
||||
|
||||
kintegrator->branched = (method == BRANCHED_PATH);
|
||||
kintegrator->branched = (method == BRANCHED_PATH) && device->info.has_branched_path;
|
||||
kintegrator->volume_decoupled = device->info.has_volume_decoupled;
|
||||
kintegrator->diffuse_samples = diffuse_samples;
|
||||
kintegrator->glossy_samples = glossy_samples;
|
||||
@@ -179,7 +185,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
|
||||
kintegrator->volume_samples = volume_samples;
|
||||
kintegrator->start_sample = start_sample;
|
||||
|
||||
if (method == BRANCHED_PATH) {
|
||||
if (kintegrator->branched) {
|
||||
kintegrator->sample_all_lights_direct = sample_all_lights_direct;
|
||||
kintegrator->sample_all_lights_indirect = sample_all_lights_indirect;
|
||||
}
|
||||
@@ -224,7 +230,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
|
||||
/* sobol directions table */
|
||||
int max_samples = 1;
|
||||
|
||||
if (method == BRANCHED_PATH) {
|
||||
if (kintegrator->branched) {
|
||||
foreach (Light *light, scene->lights)
|
||||
max_samples = max(max_samples, light->get_samples());
|
||||
|
||||
@@ -242,45 +248,63 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
|
||||
int dimensions = PRNG_BASE_NUM + max_samples * PRNG_BOUNCE_NUM;
|
||||
dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS);
|
||||
|
||||
if (sampling_pattern == SAMPLING_PATTERN_SOBOL) {
|
||||
uint *directions = dscene->sample_pattern_lut.alloc(SOBOL_BITS * dimensions);
|
||||
if (sampling_pattern_is_modified()) {
|
||||
if (sampling_pattern == SAMPLING_PATTERN_SOBOL) {
|
||||
uint *directions = dscene->sample_pattern_lut.alloc(SOBOL_BITS * dimensions);
|
||||
|
||||
sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions);
|
||||
sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions);
|
||||
|
||||
dscene->sample_pattern_lut.copy_to_device();
|
||||
}
|
||||
else {
|
||||
constexpr int sequence_size = NUM_PMJ_SAMPLES;
|
||||
constexpr int num_sequences = NUM_PMJ_PATTERNS;
|
||||
float2 *directions = (float2 *)dscene->sample_pattern_lut.alloc(sequence_size * num_sequences *
|
||||
2);
|
||||
TaskPool pool;
|
||||
for (int j = 0; j < num_sequences; ++j) {
|
||||
float2 *sequence = directions + j * sequence_size;
|
||||
pool.push(
|
||||
function_bind(&progressive_multi_jitter_02_generate_2D, sequence, sequence_size, j));
|
||||
dscene->sample_pattern_lut.copy_to_device();
|
||||
}
|
||||
else {
|
||||
constexpr int sequence_size = NUM_PMJ_SAMPLES;
|
||||
constexpr int num_sequences = NUM_PMJ_PATTERNS;
|
||||
float2 *directions = (float2 *)dscene->sample_pattern_lut.alloc(sequence_size *
|
||||
num_sequences * 2);
|
||||
TaskPool pool;
|
||||
for (int j = 0; j < num_sequences; ++j) {
|
||||
float2 *sequence = directions + j * sequence_size;
|
||||
pool.push(
|
||||
function_bind(&progressive_multi_jitter_02_generate_2D, sequence, sequence_size, j));
|
||||
}
|
||||
pool.wait_work();
|
||||
dscene->sample_pattern_lut.copy_to_device();
|
||||
}
|
||||
pool.wait_work();
|
||||
dscene->sample_pattern_lut.copy_to_device();
|
||||
}
|
||||
|
||||
clear_modified();
|
||||
}
|
||||
|
||||
void Integrator::device_free(Device *, DeviceScene *dscene)
|
||||
void Integrator::device_free(Device *, DeviceScene *dscene, bool force_free)
|
||||
{
|
||||
dscene->sample_pattern_lut.free();
|
||||
dscene->sample_pattern_lut.free_if_need_realloc(force_free);
|
||||
}
|
||||
|
||||
void Integrator::tag_update(Scene *scene)
|
||||
void Integrator::tag_update(Scene *scene, uint32_t flag)
|
||||
{
|
||||
foreach (Shader *shader, scene->shaders) {
|
||||
if (shader->has_integrator_dependency) {
|
||||
scene->shader_manager->need_update = true;
|
||||
break;
|
||||
if (flag & UPDATE_ALL) {
|
||||
tag_modified();
|
||||
}
|
||||
|
||||
if (flag & (AO_PASS_MODIFIED | BACKGROUND_AO_MODIFIED)) {
|
||||
/* tag only the ao_bounces socket as modified so we avoid updating sample_pattern_lut
|
||||
* unnecessarily */
|
||||
tag_ao_bounces_modified();
|
||||
}
|
||||
|
||||
if (filter_glossy_is_modified()) {
|
||||
foreach (Shader *shader, scene->shaders) {
|
||||
if (shader->has_integrator_dependency) {
|
||||
scene->shader_manager->tag_update(scene, ShaderManager::INTEGRATOR_MODIFIED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tag_modified();
|
||||
|
||||
if (motion_blur_is_modified()) {
|
||||
scene->object_manager->tag_update(scene, ObjectManager::MOTION_BLUR_MODIFIED);
|
||||
scene->camera->tag_modified();
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -89,13 +89,23 @@ class Integrator : public Node {
|
||||
|
||||
NODE_SOCKET_API(SamplingPattern, sampling_pattern)
|
||||
|
||||
enum : uint32_t {
|
||||
AO_PASS_MODIFIED = (1 << 0),
|
||||
BACKGROUND_AO_MODIFIED = (1 << 1),
|
||||
|
||||
/* tag everything in the manager for an update */
|
||||
UPDATE_ALL = ~0u,
|
||||
|
||||
UPDATE_NONE = 0u,
|
||||
};
|
||||
|
||||
Integrator();
|
||||
~Integrator();
|
||||
|
||||
void device_update(Device *device, DeviceScene *dscene, Scene *scene);
|
||||
void device_free(Device *device, DeviceScene *dscene);
|
||||
void device_free(Device *device, DeviceScene *dscene, bool force_free = false);
|
||||
|
||||
void tag_update(Scene *scene);
|
||||
void tag_update(Scene *scene, uint32_t flag);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -162,7 +162,9 @@ Light::Light() : Node(node_type)
|
||||
|
||||
void Light::tag_update(Scene *scene)
|
||||
{
|
||||
scene->light_manager->need_update = is_modified();
|
||||
if (is_modified()) {
|
||||
scene->light_manager->tag_update(scene, LightManager::LIGHT_MODIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
bool Light::has_contribution(Scene *scene)
|
||||
@@ -183,7 +185,7 @@ bool Light::has_contribution(Scene *scene)
|
||||
|
||||
LightManager::LightManager()
|
||||
{
|
||||
need_update = true;
|
||||
update_flags = UPDATE_ALL;
|
||||
need_update_background = true;
|
||||
use_light_visibility = false;
|
||||
last_background_enabled = false;
|
||||
@@ -962,7 +964,7 @@ void LightManager::device_update(Device *device,
|
||||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
@@ -1000,7 +1002,7 @@ void LightManager::device_update(Device *device,
|
||||
|
||||
scene->film->set_use_light_visibility(use_light_visibility);
|
||||
|
||||
need_update = false;
|
||||
update_flags = UPDATE_NONE;
|
||||
need_update_background = false;
|
||||
}
|
||||
|
||||
@@ -1015,9 +1017,14 @@ void LightManager::device_free(Device *, DeviceScene *dscene, const bool free_ba
|
||||
dscene->ies_lights.free();
|
||||
}
|
||||
|
||||
void LightManager::tag_update(Scene * /*scene*/)
|
||||
void LightManager::tag_update(Scene * /*scene*/, uint32_t flag)
|
||||
{
|
||||
need_update = true;
|
||||
update_flags |= flag;
|
||||
}
|
||||
|
||||
bool LightManager::need_update() const
|
||||
{
|
||||
return update_flags != UPDATE_NONE;
|
||||
}
|
||||
|
||||
int LightManager::add_ies_from_file(const string &filename)
|
||||
@@ -1063,7 +1070,7 @@ int LightManager::add_ies(const string &content)
|
||||
ies_slots[slot]->users = 1;
|
||||
ies_slots[slot]->hash = hash;
|
||||
|
||||
need_update = true;
|
||||
update_flags = UPDATE_ALL;
|
||||
need_update_background = true;
|
||||
|
||||
return slot;
|
||||
@@ -1082,8 +1089,10 @@ void LightManager::remove_ies(int slot)
|
||||
ies_slots[slot]->users--;
|
||||
|
||||
/* If the slot has no more users, update the device to remove it. */
|
||||
need_update |= (ies_slots[slot]->users == 0);
|
||||
need_update_background |= need_update;
|
||||
if (ies_slots[slot]->users == 0) {
|
||||
update_flags |= UPDATE_ALL;
|
||||
need_update_background = true;
|
||||
}
|
||||
}
|
||||
|
||||
void LightManager::device_update_ies(DeviceScene *dscene)
|
||||
|
@@ -91,8 +91,23 @@ class Light : public Node {
|
||||
|
||||
class LightManager {
|
||||
public:
|
||||
enum : uint32_t {
|
||||
MESH_NEED_REBUILD = (1 << 0),
|
||||
EMISSIVE_MESH_MODIFIED = (1 << 1),
|
||||
LIGHT_MODIFIED = (1 << 2),
|
||||
LIGHT_ADDED = (1 << 3),
|
||||
LIGHT_REMOVED = (1 << 4),
|
||||
OBJECT_MANAGER = (1 << 5),
|
||||
SHADER_COMPILED = (1 << 6),
|
||||
SHADER_MODIFIED = (1 << 7),
|
||||
|
||||
/* tag everything in the manager for an update */
|
||||
UPDATE_ALL = ~0u,
|
||||
|
||||
UPDATE_NONE = 0u,
|
||||
};
|
||||
|
||||
bool use_light_visibility;
|
||||
bool need_update;
|
||||
|
||||
/* Need to update background (including multiple importance map) */
|
||||
bool need_update_background;
|
||||
@@ -108,7 +123,9 @@ class LightManager {
|
||||
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
|
||||
void device_free(Device *device, DeviceScene *dscene, const bool free_background = true);
|
||||
|
||||
void tag_update(Scene *scene);
|
||||
void tag_update(Scene *scene, uint32_t flag);
|
||||
|
||||
bool need_update() const;
|
||||
|
||||
/* Check whether there is a background light. */
|
||||
bool has_background_light(Scene *scene);
|
||||
@@ -145,6 +162,8 @@ class LightManager {
|
||||
|
||||
bool last_background_enabled;
|
||||
int last_background_resolution;
|
||||
|
||||
uint32_t update_flags;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -805,34 +805,42 @@ void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, ui
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::pack_primitives(PackedBVH &pack, int object, uint visibility)
|
||||
void Mesh::pack_primitives(ccl::PackedBVH *pack, int object, uint visibility, bool pack_all)
|
||||
{
|
||||
if (triangles.empty())
|
||||
return;
|
||||
|
||||
const size_t num_prims = num_triangles();
|
||||
pack.prim_tri_index.reserve(pack.prim_tri_index.size() + num_prims);
|
||||
pack.prim_tri_verts.reserve(pack.prim_tri_verts.size() + num_prims * 3);
|
||||
pack.prim_type.reserve(pack.prim_type.size() + num_prims);
|
||||
pack.prim_visibility.reserve(pack.prim_visibility.size() + num_prims);
|
||||
pack.prim_index.reserve(pack.prim_index.size() + num_prims);
|
||||
pack.prim_object.reserve(pack.prim_object.size() + num_prims);
|
||||
// 'pack.prim_time' is unused by Embree and OptiX
|
||||
|
||||
/* Use prim_offset for indexing as it is computed per geometry type, and prim_tri_verts does not
|
||||
* contain data for Hair geometries. */
|
||||
float4 *prim_tri_verts = &pack->prim_tri_verts[prim_offset * 3];
|
||||
// 'pack->prim_time' is unused by Embree and OptiX
|
||||
|
||||
uint type = has_motion_blur() ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE;
|
||||
|
||||
if (pack_all) {
|
||||
/* Use optix_prim_offset for indexing as those arrays also contain data for Hair geometries. */
|
||||
unsigned int *prim_tri_index = &pack->prim_tri_index[optix_prim_offset];
|
||||
int *prim_type = &pack->prim_type[optix_prim_offset];
|
||||
unsigned int *prim_visibility = &pack->prim_visibility[optix_prim_offset];
|
||||
int *prim_index = &pack->prim_index[optix_prim_offset];
|
||||
int *prim_object = &pack->prim_object[optix_prim_offset];
|
||||
|
||||
for (size_t k = 0; k < num_prims; ++k) {
|
||||
prim_tri_index[k] = (prim_offset + k) * 3;
|
||||
prim_type[k] = type;
|
||||
prim_index[k] = prim_offset + k;
|
||||
prim_object[k] = object;
|
||||
prim_visibility[k] = visibility;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t k = 0; k < num_prims; ++k) {
|
||||
pack.prim_tri_index.push_back_reserved(pack.prim_tri_verts.size());
|
||||
|
||||
const Mesh::Triangle t = get_triangle(k);
|
||||
pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[0]]));
|
||||
pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[1]]));
|
||||
pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[2]]));
|
||||
|
||||
pack.prim_type.push_back_reserved(type);
|
||||
pack.prim_visibility.push_back_reserved(visibility);
|
||||
pack.prim_index.push_back_reserved(k + prim_offset);
|
||||
pack.prim_object.push_back_reserved(object);
|
||||
prim_tri_verts[k * 3] = float3_to_float4(verts[t.v[0]]);
|
||||
prim_tri_verts[k * 3 + 1] = float3_to_float4(verts[t.v[1]]);
|
||||
prim_tri_verts[k * 3 + 2] = float3_to_float4(verts[t.v[2]]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -232,7 +232,7 @@ class Mesh : public Geometry {
|
||||
size_t tri_offset);
|
||||
void pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset);
|
||||
|
||||
void pack_primitives(PackedBVH &pack, int object, uint visibility) override;
|
||||
void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) override;
|
||||
|
||||
void tessellate(DiagSplit *split);
|
||||
|
||||
|
@@ -153,6 +153,10 @@ void Object::update_motion()
|
||||
|
||||
void Object::compute_bounds(bool motion_blur)
|
||||
{
|
||||
if (!is_modified() && !geometry->is_modified()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BoundBox mbounds = geometry->bounds;
|
||||
|
||||
if (motion_blur && use_motion()) {
|
||||
@@ -205,20 +209,39 @@ void Object::apply_transform(bool apply_to_motion)
|
||||
|
||||
void Object::tag_update(Scene *scene)
|
||||
{
|
||||
uint32_t flag = ObjectManager::UPDATE_NONE;
|
||||
|
||||
if (is_modified()) {
|
||||
flag |= ObjectManager::OBJECT_MODIFIED;
|
||||
|
||||
if (use_holdout_is_modified()) {
|
||||
flag |= ObjectManager::HOLDOUT_MODIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
if (geometry) {
|
||||
if (geometry->transform_applied)
|
||||
geometry->tag_modified();
|
||||
if (tfm_is_modified()) {
|
||||
/* tag the geometry as modified so the BVH is updated, but do not tag everything as modified
|
||||
*/
|
||||
if (geometry->is_mesh() || geometry->is_volume()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geometry);
|
||||
mesh->tag_verts_modified();
|
||||
}
|
||||
else if (geometry->is_hair()) {
|
||||
Hair *hair = static_cast<Hair *>(geometry);
|
||||
hair->tag_curve_keys_modified();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Node *node, geometry->get_used_shaders()) {
|
||||
Shader *shader = static_cast<Shader *>(node);
|
||||
if (shader->get_use_mis() && shader->has_surface_emission)
|
||||
scene->light_manager->need_update = true;
|
||||
scene->light_manager->tag_update(scene, LightManager::EMISSIVE_MESH_MODIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
scene->camera->need_flags_update = true;
|
||||
scene->geometry_manager->need_update = true;
|
||||
scene->object_manager->need_update = true;
|
||||
scene->object_manager->tag_update(scene, flag);
|
||||
}
|
||||
|
||||
bool Object::use_motion() const
|
||||
@@ -361,7 +384,7 @@ int Object::get_device_index() const
|
||||
|
||||
ObjectManager::ObjectManager()
|
||||
{
|
||||
need_update = true;
|
||||
update_flags = UPDATE_ALL;
|
||||
need_flags_update = true;
|
||||
}
|
||||
|
||||
@@ -382,7 +405,9 @@ static float object_volume_density(const Transform &tfm, Geometry *geom)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state, Object *ob)
|
||||
void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state,
|
||||
Object *ob,
|
||||
bool update_all)
|
||||
{
|
||||
KernelObject &kobject = state->objects[ob->index];
|
||||
Transform *object_motion_pass = state->object_motion_pass;
|
||||
@@ -456,8 +481,11 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
|
||||
kobject.motion_offset = state->motion_offset[ob->index];
|
||||
|
||||
/* Decompose transforms for interpolation. */
|
||||
DecomposedTransform *decomp = state->object_motion + kobject.motion_offset;
|
||||
transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size());
|
||||
if (ob->tfm_is_modified() || update_all) {
|
||||
DecomposedTransform *decomp = state->object_motion + kobject.motion_offset;
|
||||
transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size());
|
||||
}
|
||||
|
||||
flag |= SD_OBJECT_MOTION;
|
||||
state->have_motion = true;
|
||||
}
|
||||
@@ -480,10 +508,14 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
|
||||
0;
|
||||
kobject.patch_map_offset = 0;
|
||||
kobject.attribute_map_offset = 0;
|
||||
uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0);
|
||||
uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0);
|
||||
kobject.cryptomatte_object = util_hash_to_float(hash_name);
|
||||
kobject.cryptomatte_asset = util_hash_to_float(hash_asset);
|
||||
|
||||
if (ob->asset_name_is_modified() || update_all) {
|
||||
uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0);
|
||||
uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0);
|
||||
kobject.cryptomatte_object = util_hash_to_float(hash_name);
|
||||
kobject.cryptomatte_asset = util_hash_to_float(hash_asset);
|
||||
}
|
||||
|
||||
kobject.shadow_terminator_offset = 1.0f / (1.0f - 0.5f * ob->shadow_terminator_offset);
|
||||
|
||||
/* Object flag. */
|
||||
@@ -544,6 +576,9 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene,
|
||||
numparticles += psys->particles.size();
|
||||
}
|
||||
|
||||
/* as all the arrays are the same size, checking only dscene.objects is sufficient */
|
||||
const bool update_all = dscene->objects.need_realloc();
|
||||
|
||||
/* Parallel object update, with grain size to avoid too much threading overhead
|
||||
* for individual objects. */
|
||||
static const int OBJECTS_PER_TASK = 32;
|
||||
@@ -551,7 +586,7 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene,
|
||||
[&](const blocked_range<size_t> &r) {
|
||||
for (size_t i = r.begin(); i != r.end(); i++) {
|
||||
Object *ob = state.scene->objects[i];
|
||||
device_update_object_transform(&state, ob);
|
||||
device_update_object_transform(&state, ob, update_all);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -559,7 +594,7 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene,
|
||||
return;
|
||||
}
|
||||
|
||||
dscene->objects.copy_to_device();
|
||||
dscene->objects.copy_to_device_if_modified();
|
||||
if (state.need_motion == Scene::MOTION_PASS) {
|
||||
dscene->object_motion_pass.copy_to_device();
|
||||
}
|
||||
@@ -569,6 +604,10 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene,
|
||||
|
||||
dscene->data.bvh.have_motion = state.have_motion;
|
||||
dscene->data.bvh.have_curves = state.have_curves;
|
||||
|
||||
dscene->objects.clear_modified();
|
||||
dscene->object_motion_pass.clear_modified();
|
||||
dscene->object_motion.clear_modified();
|
||||
}
|
||||
|
||||
void ObjectManager::device_update(Device *device,
|
||||
@@ -576,12 +615,28 @@ void ObjectManager::device_update(Device *device,
|
||||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
if (update_flags & (OBJECT_ADDED | OBJECT_REMOVED)) {
|
||||
dscene->objects.tag_realloc();
|
||||
dscene->object_motion_pass.tag_realloc();
|
||||
dscene->object_motion.tag_realloc();
|
||||
dscene->object_flag.tag_realloc();
|
||||
dscene->object_volume_step.tag_realloc();
|
||||
}
|
||||
|
||||
if (update_flags & HOLDOUT_MODIFIED) {
|
||||
dscene->object_flag.tag_modified();
|
||||
}
|
||||
|
||||
if (update_flags & PARTICLE_MODIFIED) {
|
||||
dscene->objects.tag_modified();
|
||||
}
|
||||
|
||||
VLOG(1) << "Total " << scene->objects.size() << " objects.";
|
||||
|
||||
device_free(device, dscene);
|
||||
device_free(device, dscene, false);
|
||||
|
||||
if (scene->objects.size() == 0)
|
||||
return;
|
||||
@@ -597,6 +652,16 @@ void ObjectManager::device_update(Device *device,
|
||||
int index = 0;
|
||||
foreach (Object *object, scene->objects) {
|
||||
object->index = index++;
|
||||
|
||||
/* this is a bit too broad, however a bigger refactor might be needed to properly separate
|
||||
* update each type of data (transform, flags, etc.) */
|
||||
if (object->is_modified()) {
|
||||
dscene->objects.tag_modified();
|
||||
dscene->object_motion_pass.tag_modified();
|
||||
dscene->object_motion.tag_modified();
|
||||
dscene->object_flag.tag_modified();
|
||||
dscene->object_volume_step.tag_modified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -638,7 +703,7 @@ void ObjectManager::device_update(Device *device,
|
||||
void ObjectManager::device_update_flags(
|
||||
Device *, DeviceScene *dscene, Scene *scene, Progress & /*progress*/, bool bounds_valid)
|
||||
{
|
||||
if (!need_update && !need_flags_update)
|
||||
if (!need_update() && !need_flags_update)
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
@@ -647,7 +712,7 @@ void ObjectManager::device_update_flags(
|
||||
}
|
||||
});
|
||||
|
||||
need_update = false;
|
||||
update_flags = UPDATE_NONE;
|
||||
need_flags_update = false;
|
||||
|
||||
if (scene->objects.size() == 0)
|
||||
@@ -717,6 +782,9 @@ void ObjectManager::device_update_flags(
|
||||
/* Copy object flag. */
|
||||
dscene->object_flag.copy_to_device();
|
||||
dscene->object_volume_step.copy_to_device();
|
||||
|
||||
dscene->object_flag.clear_modified();
|
||||
dscene->object_volume_step.clear_modified();
|
||||
}
|
||||
|
||||
void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Scene *scene)
|
||||
@@ -764,13 +832,13 @@ void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Sc
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectManager::device_free(Device *, DeviceScene *dscene)
|
||||
void ObjectManager::device_free(Device *, DeviceScene *dscene, bool force_free)
|
||||
{
|
||||
dscene->objects.free();
|
||||
dscene->object_motion_pass.free();
|
||||
dscene->object_motion.free();
|
||||
dscene->object_flag.free();
|
||||
dscene->object_volume_step.free();
|
||||
dscene->objects.free_if_need_realloc(force_free);
|
||||
dscene->object_motion_pass.free_if_need_realloc(force_free);
|
||||
dscene->object_motion.free_if_need_realloc(force_free);
|
||||
dscene->object_flag.free_if_need_realloc(force_free);
|
||||
dscene->object_volume_step.free_if_need_realloc(force_free);
|
||||
}
|
||||
|
||||
void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress)
|
||||
@@ -841,11 +909,21 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, P
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectManager::tag_update(Scene *scene)
|
||||
void ObjectManager::tag_update(Scene *scene, uint32_t flag)
|
||||
{
|
||||
need_update = true;
|
||||
scene->geometry_manager->need_update = true;
|
||||
scene->light_manager->need_update = true;
|
||||
update_flags |= flag;
|
||||
|
||||
/* avoid infinite loops if the geometry manager tagged us for an update */
|
||||
if ((flag & GEOMETRY_MANAGER) == 0) {
|
||||
scene->geometry_manager->tag_update(scene, GeometryManager::OBJECT_MANAGER);
|
||||
}
|
||||
|
||||
scene->light_manager->tag_update(scene, LightManager::OBJECT_MANAGER);
|
||||
}
|
||||
|
||||
bool ObjectManager::need_update() const
|
||||
{
|
||||
return update_flags != UPDATE_NONE;
|
||||
}
|
||||
|
||||
string ObjectManager::get_cryptomatte_objects(Scene *scene)
|
||||
|
@@ -122,8 +122,24 @@ class Object : public Node {
|
||||
/* Object Manager */
|
||||
|
||||
class ObjectManager {
|
||||
uint32_t update_flags;
|
||||
|
||||
public:
|
||||
bool need_update;
|
||||
enum : uint32_t {
|
||||
PARTICLE_MODIFIED = (1 << 0),
|
||||
GEOMETRY_MANAGER = (1 << 1),
|
||||
MOTION_BLUR_MODIFIED = (1 << 2),
|
||||
OBJECT_ADDED = (1 << 3),
|
||||
OBJECT_REMOVED = (1 << 4),
|
||||
OBJECT_MODIFIED = (1 << 5),
|
||||
HOLDOUT_MODIFIED = (1 << 6),
|
||||
|
||||
/* tag everything in the manager for an update */
|
||||
UPDATE_ALL = ~0u,
|
||||
|
||||
UPDATE_NONE = 0u,
|
||||
};
|
||||
|
||||
bool need_flags_update;
|
||||
|
||||
ObjectManager();
|
||||
@@ -139,9 +155,11 @@ class ObjectManager {
|
||||
bool bounds_valid = true);
|
||||
void device_update_mesh_offsets(Device *device, DeviceScene *dscene, Scene *scene);
|
||||
|
||||
void device_free(Device *device, DeviceScene *dscene);
|
||||
void device_free(Device *device, DeviceScene *dscene, bool force_free);
|
||||
|
||||
void tag_update(Scene *scene);
|
||||
void tag_update(Scene *scene, uint32_t flag);
|
||||
|
||||
bool need_update() const;
|
||||
|
||||
void apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress);
|
||||
|
||||
@@ -149,7 +167,9 @@ class ObjectManager {
|
||||
string get_cryptomatte_assets(Scene *scene);
|
||||
|
||||
protected:
|
||||
void device_update_object_transform(UpdateObjectTransformState *state, Object *ob);
|
||||
void device_update_object_transform(UpdateObjectTransformState *state,
|
||||
Object *ob,
|
||||
bool update_all);
|
||||
void device_update_object_transform_task(UpdateObjectTransformState *state);
|
||||
bool device_update_object_transform_pop_work(UpdateObjectTransformState *state,
|
||||
int *start_index,
|
||||
|
@@ -96,7 +96,7 @@ void OSLShaderManager::device_update(Device *device,
|
||||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
@@ -132,7 +132,7 @@ void OSLShaderManager::device_update(Device *device,
|
||||
compiler.compile(og, shader);
|
||||
|
||||
if (shader->get_use_mis() && shader->has_surface_emission)
|
||||
scene->light_manager->need_update = true;
|
||||
scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
|
||||
}
|
||||
|
||||
/* setup shader engine */
|
||||
@@ -147,7 +147,7 @@ void OSLShaderManager::device_update(Device *device,
|
||||
foreach (Shader *shader, scene->shaders)
|
||||
shader->clear_modified();
|
||||
|
||||
need_update = false;
|
||||
update_flags = UPDATE_NONE;
|
||||
|
||||
/* add special builtin texture types */
|
||||
services->textures.insert(ustring("@ao"), new OSLTextureHandle(OSLTextureHandle::AO));
|
||||
@@ -323,7 +323,7 @@ bool OSLShaderManager::osl_compile(const string &inputfile, const string &output
|
||||
string include_path_arg = string("-I") + shader_path;
|
||||
options.push_back(include_path_arg);
|
||||
|
||||
stdosl_path = path_get("shader/stdcycles.h");
|
||||
stdosl_path = path_join(shader_path, "stdcycles.h");
|
||||
|
||||
/* compile */
|
||||
OSL::OSLCompiler *compiler = new OSL::OSLCompiler(&OSL::ErrorHandler::default_handler());
|
||||
|
@@ -46,14 +46,14 @@ ParticleSystem::~ParticleSystem()
|
||||
|
||||
void ParticleSystem::tag_update(Scene *scene)
|
||||
{
|
||||
scene->particle_system_manager->need_update = true;
|
||||
scene->particle_system_manager->tag_update(scene);
|
||||
}
|
||||
|
||||
/* Particle System Manager */
|
||||
|
||||
ParticleSystemManager::ParticleSystemManager()
|
||||
{
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
ParticleSystemManager::~ParticleSystemManager()
|
||||
@@ -109,7 +109,7 @@ void ParticleSystemManager::device_update(Device *device,
|
||||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
@@ -128,7 +128,7 @@ void ParticleSystemManager::device_update(Device *device,
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
|
||||
need_update = false;
|
||||
need_update_ = false;
|
||||
}
|
||||
|
||||
void ParticleSystemManager::device_free(Device *, DeviceScene *dscene)
|
||||
@@ -138,7 +138,12 @@ void ParticleSystemManager::device_free(Device *, DeviceScene *dscene)
|
||||
|
||||
void ParticleSystemManager::tag_update(Scene * /*scene*/)
|
||||
{
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
bool ParticleSystemManager::need_update() const
|
||||
{
|
||||
return need_update_;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -57,9 +57,9 @@ class ParticleSystem : public Node {
|
||||
/* ParticleSystem Manager */
|
||||
|
||||
class ParticleSystemManager {
|
||||
public:
|
||||
bool need_update;
|
||||
bool need_update_;
|
||||
|
||||
public:
|
||||
ParticleSystemManager();
|
||||
~ParticleSystemManager();
|
||||
|
||||
@@ -71,6 +71,8 @@ class ParticleSystemManager {
|
||||
void device_free(Device *device, DeviceScene *dscene);
|
||||
|
||||
void tag_update(Scene *scene);
|
||||
|
||||
bool need_update() const;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
89
intern/cycles/render/procedural.cpp
Normal file
89
intern/cycles/render/procedural.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2011-2018 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "procedural.h"
|
||||
|
||||
#include "render/scene.h"
|
||||
#include "render/stats.h"
|
||||
|
||||
#include "util/util_foreach.h"
|
||||
#include "util/util_progress.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
NODE_ABSTRACT_DEFINE(Procedural)
|
||||
{
|
||||
NodeType *type = NodeType::add("procedural_base", NULL);
|
||||
return type;
|
||||
}
|
||||
|
||||
Procedural::Procedural(const NodeType *type) : Node(type)
|
||||
{
|
||||
}
|
||||
|
||||
Procedural::~Procedural()
|
||||
{
|
||||
}
|
||||
|
||||
ProceduralManager::ProceduralManager()
|
||||
{
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
ProceduralManager::~ProceduralManager()
|
||||
{
|
||||
}
|
||||
|
||||
void ProceduralManager::update(Scene *scene, Progress &progress)
|
||||
{
|
||||
if (!need_update()) {
|
||||
return;
|
||||
}
|
||||
|
||||
progress.set_status("Updating Procedurals");
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
if (scene->update_stats) {
|
||||
scene->update_stats->procedurals.times.add_entry({"update", time});
|
||||
}
|
||||
});
|
||||
|
||||
foreach (Procedural *procedural, scene->procedurals) {
|
||||
if (progress.get_cancel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
procedural->generate(scene, progress);
|
||||
}
|
||||
|
||||
if (progress.get_cancel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
need_update_ = false;
|
||||
}
|
||||
|
||||
void ProceduralManager::tag_update()
|
||||
{
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
bool ProceduralManager::need_update() const
|
||||
{
|
||||
return need_update_;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
73
intern/cycles/render/procedural.h
Normal file
73
intern/cycles/render/procedural.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2011-2018 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "graph/node.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class Progress;
|
||||
class Scene;
|
||||
|
||||
/* A Procedural is a Node which can create other Nodes before rendering starts.
|
||||
*
|
||||
* The Procedural is supposed to be the owner of any nodes that it creates. It can also create
|
||||
* Nodes directly in the Scene (through Scene.create_node), it should still be set as the owner of
|
||||
* those Nodes.
|
||||
*/
|
||||
class Procedural : public Node, public NodeOwner {
|
||||
public:
|
||||
NODE_ABSTRACT_DECLARE
|
||||
|
||||
explicit Procedural(const NodeType *type);
|
||||
virtual ~Procedural();
|
||||
|
||||
/* Called each time the ProceduralManager is tagged for an update, this function is the entry
|
||||
* point for the data generated by this Procedural. */
|
||||
virtual void generate(Scene *scene, Progress &progress) = 0;
|
||||
|
||||
/* Create a node and set this Procedural as the owner. */
|
||||
template<typename T> T *create_node()
|
||||
{
|
||||
T *node = new T();
|
||||
node->set_owner(this);
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Delete a Node created and owned by this Procedural. */
|
||||
template<typename T> void delete_node(T *node)
|
||||
{
|
||||
assert(node->get_owner() == this);
|
||||
delete node;
|
||||
}
|
||||
};
|
||||
|
||||
class ProceduralManager {
|
||||
bool need_update_;
|
||||
|
||||
public:
|
||||
ProceduralManager();
|
||||
~ProceduralManager();
|
||||
|
||||
void update(Scene *scene, Progress &progress);
|
||||
|
||||
void tag_update();
|
||||
|
||||
bool need_update() const;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "bvh/bvh.h"
|
||||
#include "device/device.h"
|
||||
#include "render/alembic.h"
|
||||
#include "render/background.h"
|
||||
#include "render/bake.h"
|
||||
#include "render/camera.h"
|
||||
@@ -29,6 +30,7 @@
|
||||
#include "render/object.h"
|
||||
#include "render/osl.h"
|
||||
#include "render/particles.h"
|
||||
#include "render/procedural.h"
|
||||
#include "render/scene.h"
|
||||
#include "render/session.h"
|
||||
#include "render/shader.h"
|
||||
@@ -114,6 +116,7 @@ Scene::Scene(const SceneParams ¶ms_, Device *device)
|
||||
image_manager = new ImageManager(device->info);
|
||||
particle_system_manager = new ParticleSystemManager();
|
||||
bake_manager = new BakeManager();
|
||||
procedural_manager = new ProceduralManager();
|
||||
kernels_loaded = false;
|
||||
|
||||
/* TODO(sergey): Check if it's indeed optimal value for the split kernel. */
|
||||
@@ -142,6 +145,9 @@ void Scene::free_memory(bool final)
|
||||
|
||||
foreach (Shader *s, shaders)
|
||||
delete s;
|
||||
/* delete procedurals before other types as they may hold pointers to those types */
|
||||
foreach (Procedural *p, procedurals)
|
||||
delete p;
|
||||
foreach (Geometry *g, geometry)
|
||||
delete g;
|
||||
foreach (Object *o, objects)
|
||||
@@ -156,15 +162,16 @@ void Scene::free_memory(bool final)
|
||||
objects.clear();
|
||||
lights.clear();
|
||||
particle_systems.clear();
|
||||
procedurals.clear();
|
||||
|
||||
if (device) {
|
||||
camera->device_free(device, &dscene, this);
|
||||
film->device_free(device, &dscene, this);
|
||||
background->device_free(device, &dscene);
|
||||
integrator->device_free(device, &dscene);
|
||||
integrator->device_free(device, &dscene, true);
|
||||
|
||||
object_manager->device_free(device, &dscene);
|
||||
geometry_manager->device_free(device, &dscene);
|
||||
object_manager->device_free(device, &dscene, true);
|
||||
geometry_manager->device_free(device, &dscene, true);
|
||||
shader_manager->device_free(device, &dscene, this);
|
||||
light_manager->device_free(device, &dscene);
|
||||
|
||||
@@ -195,6 +202,7 @@ void Scene::free_memory(bool final)
|
||||
delete image_manager;
|
||||
delete bake_manager;
|
||||
delete update_stats;
|
||||
delete procedural_manager;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,6 +244,11 @@ void Scene::device_update(Device *device_, Progress &progress)
|
||||
if (progress.get_cancel() || device->have_error())
|
||||
return;
|
||||
|
||||
procedural_manager->update(this, progress);
|
||||
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
|
||||
progress.set_status("Updating Background");
|
||||
background->device_update(device, &dscene, this);
|
||||
|
||||
@@ -386,11 +399,12 @@ bool Scene::need_update()
|
||||
|
||||
bool Scene::need_data_update()
|
||||
{
|
||||
return (background->is_modified() || image_manager->need_update || object_manager->need_update ||
|
||||
geometry_manager->need_update || light_manager->need_update ||
|
||||
lookup_tables->need_update || integrator->is_modified() || shader_manager->need_update ||
|
||||
particle_system_manager->need_update || bake_manager->need_update ||
|
||||
film->is_modified());
|
||||
return (background->is_modified() || image_manager->need_update() ||
|
||||
object_manager->need_update() || geometry_manager->need_update() ||
|
||||
light_manager->need_update() || lookup_tables->need_update() ||
|
||||
integrator->is_modified() || shader_manager->need_update() ||
|
||||
particle_system_manager->need_update() || bake_manager->need_update() ||
|
||||
film->is_modified() || procedural_manager->need_update());
|
||||
}
|
||||
|
||||
bool Scene::need_reset()
|
||||
@@ -407,12 +421,15 @@ void Scene::reset()
|
||||
camera->tag_modified();
|
||||
dicing_camera->tag_modified();
|
||||
film->tag_modified();
|
||||
background->tag_modified();
|
||||
|
||||
background->tag_update(this);
|
||||
integrator->tag_update(this);
|
||||
object_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this);
|
||||
light_manager->tag_update(this);
|
||||
integrator->tag_update(this, Integrator::UPDATE_ALL);
|
||||
object_manager->tag_update(this, ObjectManager::UPDATE_ALL);
|
||||
geometry_manager->tag_update(this, GeometryManager::UPDATE_ALL);
|
||||
light_manager->tag_update(this, LightManager::UPDATE_ALL);
|
||||
particle_system_manager->tag_update(this);
|
||||
procedural_manager->tag_update();
|
||||
}
|
||||
|
||||
void Scene::device_free()
|
||||
@@ -596,7 +613,7 @@ template<> Light *Scene::create_node<Light>()
|
||||
Light *node = new Light();
|
||||
node->set_owner(this);
|
||||
lights.push_back(node);
|
||||
light_manager->tag_update(this);
|
||||
light_manager->tag_update(this, LightManager::LIGHT_ADDED);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -605,7 +622,7 @@ template<> Mesh *Scene::create_node<Mesh>()
|
||||
Mesh *node = new Mesh();
|
||||
node->set_owner(this);
|
||||
geometry.push_back(node);
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, GeometryManager::MESH_ADDED);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -614,7 +631,7 @@ template<> Hair *Scene::create_node<Hair>()
|
||||
Hair *node = new Hair();
|
||||
node->set_owner(this);
|
||||
geometry.push_back(node);
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, GeometryManager::HAIR_ADDED);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -623,7 +640,7 @@ template<> Volume *Scene::create_node<Volume>()
|
||||
Volume *node = new Volume();
|
||||
node->set_owner(this);
|
||||
geometry.push_back(node);
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, GeometryManager::MESH_ADDED);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -632,7 +649,7 @@ template<> Object *Scene::create_node<Object>()
|
||||
Object *node = new Object();
|
||||
node->set_owner(this);
|
||||
objects.push_back(node);
|
||||
object_manager->tag_update(this);
|
||||
object_manager->tag_update(this, ObjectManager::OBJECT_ADDED);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -650,10 +667,23 @@ template<> Shader *Scene::create_node<Shader>()
|
||||
Shader *node = new Shader();
|
||||
node->set_owner(this);
|
||||
shaders.push_back(node);
|
||||
shader_manager->need_update = true;
|
||||
shader_manager->tag_update(this, ShaderManager::SHADER_ADDED);
|
||||
return node;
|
||||
}
|
||||
|
||||
template<> AlembicProcedural *Scene::create_node<AlembicProcedural>()
|
||||
{
|
||||
#ifdef WITH_ALEMBIC
|
||||
AlembicProcedural *node = new AlembicProcedural();
|
||||
node->set_owner(this);
|
||||
procedurals.push_back(node);
|
||||
procedural_manager->tag_update();
|
||||
return node;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T> void delete_node_from_array(vector<T> &nodes, T node)
|
||||
{
|
||||
for (size_t i = 0; i < nodes.size(); ++i) {
|
||||
@@ -664,43 +694,52 @@ template<typename T> void delete_node_from_array(vector<T> &nodes, T node)
|
||||
}
|
||||
|
||||
nodes.resize(nodes.size() - 1);
|
||||
|
||||
delete node;
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(Light *node)
|
||||
{
|
||||
delete_node_from_array(lights, node);
|
||||
light_manager->tag_update(this);
|
||||
light_manager->tag_update(this, LightManager::LIGHT_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(Mesh *node)
|
||||
{
|
||||
delete_node_from_array(geometry, static_cast<Geometry *>(node));
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(Hair *node)
|
||||
{
|
||||
delete_node_from_array(geometry, static_cast<Geometry *>(node));
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, GeometryManager::HAIR_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(Volume *node)
|
||||
{
|
||||
delete_node_from_array(geometry, static_cast<Geometry *>(node));
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(Geometry *node)
|
||||
{
|
||||
uint flag;
|
||||
if (node->is_hair()) {
|
||||
flag = GeometryManager::HAIR_REMOVED;
|
||||
}
|
||||
else {
|
||||
flag = GeometryManager::MESH_REMOVED;
|
||||
}
|
||||
|
||||
delete_node_from_array(geometry, node);
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, flag);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(Object *node)
|
||||
{
|
||||
delete_node_from_array(objects, node);
|
||||
object_manager->tag_update(this);
|
||||
object_manager->tag_update(this, ObjectManager::OBJECT_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(ParticleSystem *node)
|
||||
@@ -714,6 +753,21 @@ template<> void Scene::delete_node_impl(Shader * /*node*/)
|
||||
/* don't delete unused shaders, not supported */
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(Procedural *node)
|
||||
{
|
||||
delete_node_from_array(procedurals, node);
|
||||
procedural_manager->tag_update();
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(AlembicProcedural *node)
|
||||
{
|
||||
#ifdef WITH_ALEMBIC
|
||||
delete_node_impl(static_cast<Procedural *>(node));
|
||||
#else
|
||||
(void)node;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void remove_nodes_in_set(const set<T *> &nodes_set,
|
||||
vector<T *> &nodes_array,
|
||||
@@ -742,19 +796,19 @@ static void remove_nodes_in_set(const set<T *> &nodes_set,
|
||||
template<> void Scene::delete_nodes(const set<Light *> &nodes, const NodeOwner *owner)
|
||||
{
|
||||
remove_nodes_in_set(nodes, lights, owner);
|
||||
light_manager->tag_update(this);
|
||||
light_manager->tag_update(this, LightManager::LIGHT_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner)
|
||||
{
|
||||
remove_nodes_in_set(nodes, geometry, owner);
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, GeometryManager::GEOMETRY_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_nodes(const set<Object *> &nodes, const NodeOwner *owner)
|
||||
{
|
||||
remove_nodes_in_set(nodes, objects, owner);
|
||||
object_manager->tag_update(this);
|
||||
object_manager->tag_update(this, ObjectManager::OBJECT_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const NodeOwner *owner)
|
||||
@@ -768,4 +822,10 @@ template<> void Scene::delete_nodes(const set<Shader *> & /*nodes*/, const NodeO
|
||||
/* don't delete unused shaders, not supported */
|
||||
}
|
||||
|
||||
template<> void Scene::delete_nodes(const set<Procedural *> &nodes, const NodeOwner *owner)
|
||||
{
|
||||
remove_nodes_in_set(nodes, procedurals, owner);
|
||||
procedural_manager->tag_update();
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -36,6 +36,7 @@
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class AlembicProcedural;
|
||||
class AttributeRequestSet;
|
||||
class Background;
|
||||
class BVH;
|
||||
@@ -53,6 +54,8 @@ class Object;
|
||||
class ObjectManager;
|
||||
class ParticleSystemManager;
|
||||
class ParticleSystem;
|
||||
class Procedural;
|
||||
class ProceduralManager;
|
||||
class CurveSystemManager;
|
||||
class Shader;
|
||||
class ShaderManager;
|
||||
@@ -236,6 +239,7 @@ class Scene : public NodeOwner {
|
||||
vector<Light *> lights;
|
||||
vector<ParticleSystem *> particle_systems;
|
||||
vector<Pass> passes;
|
||||
vector<Procedural *> procedurals;
|
||||
|
||||
/* data managers */
|
||||
ImageManager *image_manager;
|
||||
@@ -245,6 +249,7 @@ class Scene : public NodeOwner {
|
||||
ObjectManager *object_manager;
|
||||
ParticleSystemManager *particle_system_manager;
|
||||
BakeManager *bake_manager;
|
||||
ProceduralManager *procedural_manager;
|
||||
|
||||
/* default shaders */
|
||||
Shader *default_surface;
|
||||
@@ -379,6 +384,8 @@ template<> ParticleSystem *Scene::create_node<ParticleSystem>();
|
||||
|
||||
template<> Shader *Scene::create_node<Shader>();
|
||||
|
||||
template<> AlembicProcedural *Scene::create_node<AlembicProcedural>();
|
||||
|
||||
template<> void Scene::delete_node_impl(Light *node);
|
||||
|
||||
template<> void Scene::delete_node_impl(Mesh *node);
|
||||
@@ -395,6 +402,10 @@ template<> void Scene::delete_node_impl(ParticleSystem *node);
|
||||
|
||||
template<> void Scene::delete_node_impl(Shader *node);
|
||||
|
||||
template<> void Scene::delete_node_impl(Procedural *node);
|
||||
|
||||
template<> void Scene::delete_node_impl(AlembicProcedural *node);
|
||||
|
||||
template<> void Scene::delete_nodes(const set<Light *> &nodes, const NodeOwner *owner);
|
||||
|
||||
template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner);
|
||||
@@ -405,6 +416,8 @@ template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const No
|
||||
|
||||
template<> void Scene::delete_nodes(const set<Shader *> &nodes, const NodeOwner *owner);
|
||||
|
||||
template<> void Scene::delete_nodes(const set<Procedural *> &nodes, const NodeOwner *owner);
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __SCENE_H__ */
|
||||
|
@@ -459,13 +459,21 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ
|
||||
int device_num = device->device_number(tile_device);
|
||||
|
||||
while (!tile_manager.next_tile(tile, device_num, tile_types)) {
|
||||
/* Can only steal tiles on devices that support rendering
|
||||
* This is because denoising tiles cannot be stolen (see below)
|
||||
*/
|
||||
if ((tile_types & (RenderTile::PATH_TRACE | RenderTile::BAKE)) &&
|
||||
steal_tile(rtile, tile_device, tile_lock)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Wait for denoising tiles to become available */
|
||||
if ((tile_types & RenderTile::DENOISE) && !progress.get_cancel() && tile_manager.has_tiles()) {
|
||||
denoising_cond.wait(tile_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
return steal_tile(rtile, tile_device, tile_lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* fill render tile */
|
||||
@@ -477,6 +485,7 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ
|
||||
rtile.num_samples = tile_manager.state.num_samples;
|
||||
rtile.resolution = tile_manager.state.resolution_divider;
|
||||
rtile.tile_index = tile->index;
|
||||
rtile.stealing_state = RenderTile::NO_STEALING;
|
||||
|
||||
if (tile->state == Tile::DENOISE) {
|
||||
rtile.task = RenderTile::DENOISE;
|
||||
@@ -531,6 +540,14 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ
|
||||
tile->buffers = new RenderBuffers(tile_device);
|
||||
tile->buffers->reset(buffer_params);
|
||||
}
|
||||
else if (tile->buffers->buffer.device != tile_device) {
|
||||
/* Move buffer to current tile device again in case it was stolen before.
|
||||
* Not needed for denoising since that already handles mapping of tiles and
|
||||
* neighbors to its own device. */
|
||||
if (rtile.task != RenderTile::DENOISE) {
|
||||
tile->buffers->buffer.move_device(tile_device);
|
||||
}
|
||||
}
|
||||
|
||||
tile->buffers->map_neighbor_copied = false;
|
||||
|
||||
@@ -542,11 +559,13 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ
|
||||
|
||||
if (read_bake_tile_cb) {
|
||||
/* This will read any passes needed as input for baking. */
|
||||
{
|
||||
thread_scoped_lock tile_lock(tile_mutex);
|
||||
read_bake_tile_cb(rtile);
|
||||
if (tile_manager.state.sample == tile_manager.range_start_sample) {
|
||||
{
|
||||
thread_scoped_lock tile_lock(tile_mutex);
|
||||
read_bake_tile_cb(rtile);
|
||||
}
|
||||
rtile.buffers->buffer.copy_to_device();
|
||||
}
|
||||
rtile.buffers->buffer.copy_to_device();
|
||||
}
|
||||
else {
|
||||
/* This will tag tile as IN PROGRESS in blender-side render pipeline,
|
||||
@@ -1021,13 +1040,7 @@ bool Session::update_scene()
|
||||
BakeManager *bake_manager = scene->bake_manager;
|
||||
|
||||
if (integrator->get_sampling_pattern() != SAMPLING_PATTERN_SOBOL || bake_manager->get_baking()) {
|
||||
int aa_samples = tile_manager.num_samples;
|
||||
|
||||
integrator->set_aa_samples(aa_samples);
|
||||
|
||||
if (integrator->is_modified()) {
|
||||
integrator->tag_update(scene);
|
||||
}
|
||||
integrator->set_aa_samples(tile_manager.num_samples);
|
||||
}
|
||||
|
||||
bool kernel_switch_needed = false;
|
||||
|
@@ -103,10 +103,10 @@ class SessionParams {
|
||||
|
||||
bool modified(const SessionParams ¶ms)
|
||||
{
|
||||
/* Modified means we have to recreate the session, any parameter changes
|
||||
* that can be handled by an existing Session are omitted. */
|
||||
return !(device == params.device && background == params.background &&
|
||||
progressive_refine == params.progressive_refine &&
|
||||
/* samples == params.samples && denoising_start_sample ==
|
||||
params.denoising_start_sample && */
|
||||
progressive == params.progressive && experimental == params.experimental &&
|
||||
tile_size == params.tile_size && start_resolution == params.start_resolution &&
|
||||
pixel_size == params.pixel_size && threads == params.threads &&
|
||||
@@ -117,7 +117,8 @@ class SessionParams {
|
||||
text_timeout == params.text_timeout &&
|
||||
progressive_update_timeout == params.progressive_update_timeout &&
|
||||
tile_order == params.tile_order && shadingsystem == params.shadingsystem &&
|
||||
denoising.type == params.denoising.type);
|
||||
denoising.type == params.denoising.type &&
|
||||
(denoising.use == params.denoising.use || (device.denoisers & denoising.type)));
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "device/device.h"
|
||||
|
||||
#include "render/alembic.h"
|
||||
#include "render/background.h"
|
||||
#include "render/camera.h"
|
||||
#include "render/colorspace.h"
|
||||
@@ -218,7 +219,9 @@ Shader::Shader() : Node(node_type)
|
||||
id = -1;
|
||||
used = false;
|
||||
|
||||
need_update_geometry = true;
|
||||
need_update_uvs = true;
|
||||
need_update_attribute = true;
|
||||
need_update_displacement = true;
|
||||
}
|
||||
|
||||
Shader::~Shader()
|
||||
@@ -291,7 +294,7 @@ void Shader::set_graph(ShaderGraph *graph_)
|
||||
const char *new_hash = (graph_) ? graph_->displacement_hash.c_str() : "";
|
||||
|
||||
if (strcmp(old_hash, new_hash) != 0) {
|
||||
need_update_geometry = true;
|
||||
need_update_displacement = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,13 +311,14 @@ void Shader::tag_update(Scene *scene)
|
||||
{
|
||||
/* update tag */
|
||||
tag_modified();
|
||||
scene->shader_manager->need_update = true;
|
||||
|
||||
scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
|
||||
|
||||
/* if the shader previously was emissive, update light distribution,
|
||||
* if the new shader is emissive, a light manager update tag will be
|
||||
* done in the shader manager device update. */
|
||||
if (use_mis && has_surface_emission)
|
||||
scene->light_manager->need_update = true;
|
||||
scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED);
|
||||
|
||||
/* Special handle of background MIS light for now: for some reason it
|
||||
* has use_mis set to false. We are quite close to release now, so
|
||||
@@ -323,7 +327,7 @@ void Shader::tag_update(Scene *scene)
|
||||
if (this == scene->background->get_shader(scene)) {
|
||||
scene->light_manager->need_update_background = true;
|
||||
if (scene->light_manager->has_background_light(scene)) {
|
||||
scene->light_manager->need_update = true;
|
||||
scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,17 +356,18 @@ void Shader::tag_update(Scene *scene)
|
||||
attributes.add(ATTR_STD_POSITION_UNDISPLACED);
|
||||
}
|
||||
if (displacement_method_is_modified()) {
|
||||
need_update_geometry = true;
|
||||
scene->geometry_manager->need_update = true;
|
||||
need_update_displacement = true;
|
||||
scene->geometry_manager->tag_update(scene, GeometryManager::SHADER_DISPLACEMENT_MODIFIED);
|
||||
scene->object_manager->need_flags_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* compare if the attributes changed, mesh manager will check
|
||||
* need_update_geometry, update the relevant meshes and clear it. */
|
||||
* need_update_attribute, update the relevant meshes and clear it. */
|
||||
if (attributes.modified(prev_attributes)) {
|
||||
need_update_geometry = true;
|
||||
scene->geometry_manager->need_update = true;
|
||||
need_update_attribute = true;
|
||||
scene->geometry_manager->tag_update(scene, GeometryManager::SHADER_ATTRIBUTE_MODIFIED);
|
||||
scene->procedural_manager->tag_update();
|
||||
}
|
||||
|
||||
if (has_volume != prev_has_volume || volume_step_rate != prev_volume_step_rate) {
|
||||
@@ -378,15 +383,20 @@ void Shader::tag_used(Scene *scene)
|
||||
* recompiled because it was skipped for compilation before */
|
||||
if (!used) {
|
||||
tag_modified();
|
||||
scene->shader_manager->need_update = true;
|
||||
scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
bool Shader::need_update_geometry() const
|
||||
{
|
||||
return need_update_uvs || need_update_attribute || need_update_displacement;
|
||||
}
|
||||
|
||||
/* Shader Manager */
|
||||
|
||||
ShaderManager::ShaderManager()
|
||||
{
|
||||
need_update = true;
|
||||
update_flags = UPDATE_ALL;
|
||||
beckmann_table_offset = TABLE_OFFSET_INVALID;
|
||||
|
||||
xyz_to_r = make_float3(3.2404542f, -1.5371385f, -0.4985314f);
|
||||
@@ -484,7 +494,7 @@ int ShaderManager::get_shader_id(Shader *shader, bool smooth)
|
||||
|
||||
void ShaderManager::update_shaders_used(Scene *scene)
|
||||
{
|
||||
if (!need_update) {
|
||||
if (!need_update()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -504,6 +514,21 @@ void ShaderManager::update_shaders_used(Scene *scene)
|
||||
if (scene->background->get_shader())
|
||||
scene->background->get_shader()->used = true;
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
foreach (Procedural *procedural, scene->procedurals) {
|
||||
AlembicProcedural *abc_proc = static_cast<AlembicProcedural *>(procedural);
|
||||
|
||||
foreach (Node *abc_node, abc_proc->get_objects()) {
|
||||
AlembicObject *abc_object = static_cast<AlembicObject *>(abc_node);
|
||||
|
||||
foreach (Node *node, abc_object->get_used_shaders()) {
|
||||
Shader *shader = static_cast<Shader *>(node);
|
||||
shader->used = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
foreach (Geometry *geom, scene->geometry)
|
||||
foreach (Node *node, geom->get_used_shaders()) {
|
||||
Shader *shader = static_cast<Shader *>(node);
|
||||
@@ -793,4 +818,15 @@ string ShaderManager::get_cryptomatte_materials(Scene *scene)
|
||||
return manifest;
|
||||
}
|
||||
|
||||
void ShaderManager::tag_update(Scene * /*scene*/, uint32_t /*flag*/)
|
||||
{
|
||||
/* update everything for now */
|
||||
update_flags = ShaderManager::UPDATE_ALL;
|
||||
}
|
||||
|
||||
bool ShaderManager::need_update() const
|
||||
{
|
||||
return update_flags != UPDATE_NONE;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -100,7 +100,9 @@ class Shader : public Node {
|
||||
float prev_volume_step_rate;
|
||||
|
||||
/* synchronization */
|
||||
bool need_update_geometry;
|
||||
bool need_update_uvs;
|
||||
bool need_update_attribute;
|
||||
bool need_update_displacement;
|
||||
|
||||
/* If the shader has only volume components, the surface is assumed to
|
||||
* be transparent.
|
||||
@@ -152,6 +154,8 @@ class Shader : public Node {
|
||||
void set_graph(ShaderGraph *graph);
|
||||
void tag_update(Scene *scene);
|
||||
void tag_used(Scene *scene);
|
||||
|
||||
bool need_update_geometry() const;
|
||||
};
|
||||
|
||||
/* Shader Manager virtual base class
|
||||
@@ -161,7 +165,16 @@ class Shader : public Node {
|
||||
|
||||
class ShaderManager {
|
||||
public:
|
||||
bool need_update;
|
||||
enum : uint32_t {
|
||||
SHADER_ADDED = (1 << 0),
|
||||
SHADER_MODIFIED = (1 << 2),
|
||||
INTEGRATOR_MODIFIED = (1 << 3),
|
||||
|
||||
/* tag everything in the manager for an update */
|
||||
UPDATE_ALL = ~0u,
|
||||
|
||||
UPDATE_NONE = 0u,
|
||||
};
|
||||
|
||||
static ShaderManager *create(int shadingsystem);
|
||||
virtual ~ShaderManager();
|
||||
@@ -204,9 +217,15 @@ class ShaderManager {
|
||||
|
||||
string get_cryptomatte_materials(Scene *scene);
|
||||
|
||||
void tag_update(Scene *scene, uint32_t flag);
|
||||
|
||||
bool need_update() const;
|
||||
|
||||
protected:
|
||||
ShaderManager();
|
||||
|
||||
uint32_t update_flags;
|
||||
|
||||
typedef unordered_map<ustring, uint, ustringHash> AttributeIDMap;
|
||||
AttributeIDMap unique_attribute_id;
|
||||
|
||||
|
@@ -375,6 +375,7 @@ string SceneUpdateStats::full_report()
|
||||
result += "Particles:\n" + particles.full_report(1);
|
||||
result += "SVM:\n" + svm.full_report(1);
|
||||
result += "Tables:\n" + tables.full_report(1);
|
||||
result += "Procedurals:\n" + procedurals.full_report(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -394,6 +395,7 @@ void SceneUpdateStats::clear()
|
||||
scene.times.clear();
|
||||
svm.times.clear();
|
||||
tables.times.clear();
|
||||
procedurals.times.clear();
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -219,6 +219,7 @@ class SceneUpdateStats {
|
||||
UpdateTimeStats scene;
|
||||
UpdateTimeStats svm;
|
||||
UpdateTimeStats tables;
|
||||
UpdateTimeStats procedurals;
|
||||
|
||||
string full_report();
|
||||
|
||||
|
@@ -74,7 +74,7 @@ void SVMShaderManager::device_update(Device *device,
|
||||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
@@ -125,7 +125,7 @@ void SVMShaderManager::device_update(Device *device,
|
||||
|
||||
shader->clear_modified();
|
||||
if (shader->get_use_mis() && shader->has_surface_emission) {
|
||||
scene->light_manager->need_update = true;
|
||||
scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
|
||||
}
|
||||
|
||||
/* Update the global jump table.
|
||||
@@ -159,7 +159,7 @@ void SVMShaderManager::device_update(Device *device,
|
||||
|
||||
device_update_common(device, dscene, scene, progress);
|
||||
|
||||
need_update = false;
|
||||
update_flags = UPDATE_NONE;
|
||||
|
||||
VLOG(1) << "Shader manager updated " << num_shaders << " shaders in " << time_dt() - start_time
|
||||
<< " seconds.";
|
||||
|
@@ -28,7 +28,7 @@ CCL_NAMESPACE_BEGIN
|
||||
|
||||
LookupTables::LookupTables()
|
||||
{
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
LookupTables::~LookupTables()
|
||||
@@ -38,7 +38,7 @@ LookupTables::~LookupTables()
|
||||
|
||||
void LookupTables::device_update(Device *, DeviceScene *dscene, Scene *scene)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
@@ -52,7 +52,7 @@ void LookupTables::device_update(Device *, DeviceScene *dscene, Scene *scene)
|
||||
if (lookup_tables.size() > 0)
|
||||
dscene->lookup_table.copy_to_device();
|
||||
|
||||
need_update = false;
|
||||
need_update_ = false;
|
||||
}
|
||||
|
||||
void LookupTables::device_free(Device *, DeviceScene *dscene)
|
||||
@@ -60,6 +60,11 @@ void LookupTables::device_free(Device *, DeviceScene *dscene)
|
||||
dscene->lookup_table.free();
|
||||
}
|
||||
|
||||
bool LookupTables::need_update() const
|
||||
{
|
||||
return need_update_;
|
||||
}
|
||||
|
||||
static size_t round_up_to_multiple(size_t size, size_t chunk)
|
||||
{
|
||||
return ((size + chunk - 1) / chunk) * chunk;
|
||||
@@ -69,7 +74,7 @@ size_t LookupTables::add_table(DeviceScene *dscene, vector<float> &data)
|
||||
{
|
||||
assert(data.size() > 0);
|
||||
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
|
||||
Table new_table;
|
||||
new_table.offset = 0;
|
||||
@@ -107,7 +112,7 @@ void LookupTables::remove_table(size_t *offset)
|
||||
return;
|
||||
}
|
||||
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
|
||||
list<Table>::iterator table;
|
||||
|
||||
|
@@ -30,13 +30,14 @@ enum { TABLE_CHUNK_SIZE = 256 };
|
||||
enum { TABLE_OFFSET_INVALID = -1 };
|
||||
|
||||
class LookupTables {
|
||||
bool need_update_;
|
||||
|
||||
public:
|
||||
struct Table {
|
||||
size_t offset;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
bool need_update;
|
||||
list<Table> lookup_tables;
|
||||
|
||||
LookupTables();
|
||||
@@ -45,6 +46,8 @@ class LookupTables {
|
||||
void device_update(Device *device, DeviceScene *dscene, Scene *scene);
|
||||
void device_free(Device *device, DeviceScene *dscene);
|
||||
|
||||
bool need_update() const;
|
||||
|
||||
size_t add_table(DeviceScene *dscene, vector<float> &data);
|
||||
void remove_table(size_t *offset);
|
||||
};
|
||||
|
@@ -55,11 +55,15 @@ set(SRC
|
||||
)
|
||||
|
||||
if(CXX_HAS_AVX)
|
||||
list(APPEND SRC util_avxf_avx_test.cpp)
|
||||
list(APPEND SRC
|
||||
util_avxf_avx_test.cpp
|
||||
)
|
||||
set_source_files_properties(util_avxf_avx_test.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX_KERNEL_FLAGS}")
|
||||
endif()
|
||||
if(CXX_HAS_AVX2)
|
||||
list(APPEND SRC util_avxf_avx2_test.cpp)
|
||||
list(APPEND SRC
|
||||
util_avxf_avx2_test.cpp
|
||||
)
|
||||
set_source_files_properties(util_avxf_avx2_test.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX2_KERNEL_FLAGS}")
|
||||
endif()
|
||||
|
||||
|
@@ -131,6 +131,14 @@ template<typename T, size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES> class arra
|
||||
}
|
||||
}
|
||||
|
||||
void set_data(T *ptr_, size_t datasize)
|
||||
{
|
||||
clear();
|
||||
data_ = ptr_;
|
||||
datasize_ = datasize;
|
||||
capacity_ = datasize;
|
||||
}
|
||||
|
||||
T *steal_pointer()
|
||||
{
|
||||
T *ptr = data_;
|
||||
|
@@ -62,7 +62,7 @@ void TaskPool::cancel()
|
||||
|
||||
bool TaskPool::canceled()
|
||||
{
|
||||
return tbb_group.is_canceling();
|
||||
return tbb::is_current_task_group_canceling();
|
||||
}
|
||||
|
||||
/* Task Scheduler */
|
||||
|
@@ -61,7 +61,7 @@ class TaskPool {
|
||||
void wait_work(Summary *stats = NULL); /* work and wait until all tasks are done */
|
||||
void cancel(); /* cancel all tasks and wait until they are no longer executing */
|
||||
|
||||
bool canceled(); /* for worker threads, test if canceled */
|
||||
static bool canceled(); /* For worker threads, test if current task pool canceled. */
|
||||
|
||||
protected:
|
||||
tbb::task_group tbb_group;
|
||||
|
@@ -36,7 +36,14 @@ using tbb::parallel_for;
|
||||
|
||||
static inline void parallel_for_cancel()
|
||||
{
|
||||
#if TBB_INTERFACE_VERSION_MAJOR >= 12
|
||||
tbb::task_group_context *ctx = tbb::task::current_context();
|
||||
if (ctx) {
|
||||
ctx->cancel_group_execution();
|
||||
}
|
||||
#else
|
||||
tbb::task::self().cancel_group_execution();
|
||||
#endif
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -109,7 +109,7 @@ class GHOST_DropTargetX11 {
|
||||
/* class holding internal stiff of xdnd library */
|
||||
static DndClass m_dndClass;
|
||||
|
||||
/* list of supported types to eb draggeg into */
|
||||
/* list of supported types to be dragged into */
|
||||
static Atom *m_dndTypes;
|
||||
|
||||
/* list of supported dran'n'drop actions */
|
||||
|
@@ -225,6 +225,9 @@ GHOST_SystemWin32::GHOST_SystemWin32()
|
||||
#ifdef WITH_INPUT_NDOF
|
||||
m_ndofManager = new GHOST_NDOFManagerWin32(*this);
|
||||
#endif
|
||||
|
||||
getCursorPosition(m_mousePosX, m_mousePosY);
|
||||
m_mouseTimestamp = ::GetTickCount();
|
||||
}
|
||||
|
||||
GHOST_SystemWin32::~GHOST_SystemWin32()
|
||||
@@ -533,7 +536,20 @@ GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32
|
||||
{
|
||||
if (!::GetActiveWindow())
|
||||
return GHOST_kFailure;
|
||||
return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
|
||||
|
||||
INPUT input;
|
||||
input.type = INPUT_MOUSE;
|
||||
input.mi.mouseData = 0;
|
||||
input.mi.time = ::GetTickCount();
|
||||
/* Map from virtual screen to 0-65535 inclusive. */
|
||||
input.mi.dx = (x - GetSystemMetrics(SM_XVIRTUALSCREEN)) * 65535 /
|
||||
(GetSystemMetrics(SM_CXVIRTUALSCREEN) - 1);
|
||||
input.mi.dy = (y - GetSystemMetrics(SM_YVIRTUALSCREEN)) * 65535 /
|
||||
(GetSystemMetrics(SM_CYVIRTUALSCREEN) - 1);
|
||||
input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;
|
||||
SendInput(1, &input, sizeof(input));
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys &keys) const
|
||||
@@ -942,8 +958,18 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type,
|
||||
GHOST_TabletData td = window->m_tabletInRange ? window->getLastTabletData() :
|
||||
GHOST_TABLET_DATA_NONE;
|
||||
|
||||
/* Ensure button click occurs at its intended position. */
|
||||
processCursorEvent(window);
|
||||
/* Move mouse to button event position. */
|
||||
if (!window->m_tabletInRange) {
|
||||
processCursorEvent(window);
|
||||
}
|
||||
else {
|
||||
/* Tablet should be hadling inbetween mouse moves, only move to event position. */
|
||||
DWORD msgPos = ::GetMessagePos();
|
||||
int msgPosX = GET_X_LPARAM(msgPos);
|
||||
int msgPosY = GET_Y_LPARAM(msgPos);
|
||||
system->pushEvent(new GHOST_EventCursor(
|
||||
::GetMessageTime(), GHOST_kEventCursorMove, window, msgPosX, msgPosY, td));
|
||||
}
|
||||
|
||||
window->updateMouseCapture(type == GHOST_kEventButtonDown ? MousePressed : MouseReleased);
|
||||
return new GHOST_EventButton(system->getMilliSeconds(), type, window, mask, td);
|
||||
@@ -1101,18 +1127,79 @@ void GHOST_SystemWin32::processPointerEvent(
|
||||
system->setCursorPosition(pointerInfo[0].pixelLocation.x, pointerInfo[0].pixelLocation.y);
|
||||
}
|
||||
|
||||
GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window)
|
||||
void GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window)
|
||||
{
|
||||
/* Cursor moves handled by tablets while active. */
|
||||
if (window->m_tabletInRange) {
|
||||
return;
|
||||
}
|
||||
|
||||
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
|
||||
|
||||
DWORD msgPos = ::GetMessagePos();
|
||||
GHOST_TInt32 x_screen = GET_X_LPARAM(msgPos);
|
||||
GHOST_TInt32 y_screen = GET_Y_LPARAM(msgPos);
|
||||
GHOST_TInt32 x_accum = 0, y_accum = 0;
|
||||
LONG msgTime = ::GetMessageTime();
|
||||
|
||||
if (window->getCursorGrabModeIsWarp() && !window->m_tabletInRange) {
|
||||
GHOST_TInt32 x_new = x_screen;
|
||||
GHOST_TInt32 y_new = y_screen;
|
||||
/* GetMessagePointsEx processes points as 16 bit integers and can fail or return erroneous values
|
||||
* if negative input is not truncated. */
|
||||
int msgPosX = GET_X_LPARAM(msgPos) & 0x0000FFFF;
|
||||
int msgPosY = GET_Y_LPARAM(msgPos) & 0x0000FFFF;
|
||||
|
||||
const int maxPoints = 64;
|
||||
MOUSEMOVEPOINT currentPoint = {msgPosX, msgPosY, (DWORD)msgTime, 0};
|
||||
MOUSEMOVEPOINT points[maxPoints] = {0};
|
||||
/* GetMouseMovePointsEx returns the number of points returned that are less than or equal to the
|
||||
* requested point. If the requested point is the most recent, this returns up to 64 requested
|
||||
* points. */
|
||||
int numPoints = ::GetMouseMovePointsEx(
|
||||
sizeof(MOUSEMOVEPOINT), ¤tPoint, points, maxPoints, GMMP_USE_DISPLAY_POINTS);
|
||||
|
||||
if (numPoints == -1) {
|
||||
/* Points at edge of screen are often not in the queue, use the message's point instead. */
|
||||
numPoints = 1;
|
||||
points[0] = currentPoint;
|
||||
}
|
||||
|
||||
GHOST_TInt32 x_accum = 0, y_accum = 0;
|
||||
window->getCursorGrabAccum(x_accum, y_accum);
|
||||
|
||||
/* Points are in reverse chronological order. Find least recent, unprocessed mouse move. */
|
||||
int i;
|
||||
for (i = 0; i < numPoints; i++) {
|
||||
if (points[i].time < system->m_mouseTimestamp) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* GetMouseMovePointsEx returns 16 bit number as 32 bit. If negative, we need to sign extend.
|
||||
*/
|
||||
points[i].x = points[i].x > 32767 ? points[i].x | 0xFFFF0000 : points[i].x;
|
||||
points[i].y = points[i].y > 32767 ? points[i].y | 0xFFFF0000 : points[i].y;
|
||||
|
||||
if (points[i].time == system->m_mouseTimestamp && points[i].x == system->m_mousePosX &&
|
||||
points[i].y == system->m_mousePosY) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (--i >= 0) {
|
||||
system->pushEvent(new GHOST_EventCursor(system->getMilliSeconds(),
|
||||
GHOST_kEventCursorMove,
|
||||
window,
|
||||
points[i].x + x_accum,
|
||||
points[i].y + y_accum,
|
||||
GHOST_TABLET_DATA_NONE));
|
||||
}
|
||||
|
||||
DWORD lastTimestamp = points[0].time;
|
||||
|
||||
/* Check if we need to wrap the cursor. */
|
||||
if (window->getCursorGrabModeIsWarp()) {
|
||||
/* Wrap based on current cursor position in case Win32 mouse move queue is out of order due to
|
||||
* prior wrap. */
|
||||
POINT point;
|
||||
::GetCursorPos(&point);
|
||||
GHOST_TInt32 x_current = point.x;
|
||||
GHOST_TInt32 y_current = point.y;
|
||||
GHOST_TInt32 x_wrap = point.x;
|
||||
GHOST_TInt32 y_wrap = point.y;
|
||||
GHOST_Rect bounds;
|
||||
|
||||
/* Fallback to window bounds. */
|
||||
@@ -1122,23 +1209,24 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
|
||||
|
||||
/* Could also clamp to screen bounds wrap with a window outside the view will fail atm.
|
||||
* Use offset of 8 in case the window is at screen bounds. */
|
||||
bounds.wrapPoint(x_new, y_new, 2, window->getCursorGrabAxis());
|
||||
bounds.wrapPoint(x_wrap, y_wrap, 2, window->getCursorGrabAxis());
|
||||
|
||||
window->getCursorGrabAccum(x_accum, y_accum);
|
||||
if (x_new != x_screen || y_new != y_screen) {
|
||||
system->setCursorPosition(x_new, y_new); /* wrap */
|
||||
window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new));
|
||||
if (x_wrap != x_current || y_wrap != y_current) {
|
||||
system->setCursorPosition(x_wrap, y_wrap);
|
||||
window->setCursorGrabAccum(x_accum + (x_current - x_wrap), y_accum + (y_current - y_wrap));
|
||||
|
||||
/* First message after SendInput wrap is invalid for unknown reasons, skip events until one
|
||||
* tick after SendInput event time. */
|
||||
lastTimestamp = ::GetTickCount() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TabletData td = window->m_tabletInRange ? window->getLastTabletData() :
|
||||
GHOST_TABLET_DATA_NONE;
|
||||
return new GHOST_EventCursor(system->getMilliSeconds(),
|
||||
GHOST_kEventCursorMove,
|
||||
window,
|
||||
x_screen + x_accum,
|
||||
y_screen + y_accum,
|
||||
td);
|
||||
system->m_mousePosX = points[0].x;
|
||||
system->m_mousePosY = points[0].y;
|
||||
/* Use latest time, checking for overflow. */
|
||||
if (lastTimestamp > system->m_mouseTimestamp || ::GetTickCount() < system->m_mouseTimestamp) {
|
||||
system->m_mouseTimestamp = lastTimestamp;
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam)
|
||||
@@ -1631,7 +1719,8 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
||||
}
|
||||
|
||||
if (!window->m_tabletInRange) {
|
||||
event = processCursorEvent(window);
|
||||
processCursorEvent(window);
|
||||
eventHandled = true;
|
||||
}
|
||||
break;
|
||||
case WM_MOUSEWHEEL: {
|
||||
@@ -1677,6 +1766,9 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
||||
case WM_MOUSELEAVE:
|
||||
window->m_mousePresent = false;
|
||||
window->setWintabOverlap(false);
|
||||
if (!window->m_tabletInRange) {
|
||||
processCursorEvent(window);
|
||||
}
|
||||
break;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Mouse events, ignored
|
||||
|
@@ -340,9 +340,8 @@ class GHOST_SystemWin32 : public GHOST_System {
|
||||
/**
|
||||
* Creates cursor event.
|
||||
* \param window: The window receiving the event (the active window).
|
||||
* \return The event created.
|
||||
*/
|
||||
static GHOST_EventCursor *processCursorEvent(GHOST_WindowWin32 *window);
|
||||
static void processCursorEvent(GHOST_WindowWin32 *window);
|
||||
|
||||
/**
|
||||
* Handles a mouse wheel event.
|
||||
@@ -463,16 +462,23 @@ class GHOST_SystemWin32 : public GHOST_System {
|
||||
__int64 m_lfstart;
|
||||
/** AltGr on current keyboard layout. */
|
||||
bool m_hasAltGr;
|
||||
/** language identifier. */
|
||||
/** Language identifier. */
|
||||
WORD m_langId;
|
||||
/** stores keyboard layout. */
|
||||
/** Stores keyboard layout. */
|
||||
HKL m_keylayout;
|
||||
|
||||
/** Console status */
|
||||
/** Console status. */
|
||||
int m_consoleStatus;
|
||||
|
||||
/** Wheel delta accumulator */
|
||||
/** Wheel delta accumulator. */
|
||||
int m_wheelDeltaAccum;
|
||||
|
||||
/** Last mouse x position. */
|
||||
int m_mousePosX;
|
||||
/** Last mouse y position. */
|
||||
int m_mousePosY;
|
||||
/** Last mouse timestamp. */
|
||||
DWORD m_mouseTimestamp;
|
||||
};
|
||||
|
||||
inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys &keys) const
|
||||
|
@@ -49,12 +49,6 @@ set(LIB
|
||||
)
|
||||
|
||||
if(WIN32 AND NOT UNIX)
|
||||
list(APPEND SRC
|
||||
intern/mmap_win.c
|
||||
|
||||
mmap_win.h
|
||||
)
|
||||
|
||||
list(APPEND INC_SYS
|
||||
${PTHREADS_INC}
|
||||
)
|
||||
|
@@ -122,7 +122,7 @@ extern void *(*MEM_calloc_arrayN)(size_t len,
|
||||
/**
|
||||
* Allocate a block of memory of size len, with tag name str. The
|
||||
* name must be a static, because only a pointer to it is stored !
|
||||
* */
|
||||
*/
|
||||
extern void *(*MEM_mallocN)(size_t len, const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_ALLOC_SIZE(1) ATTR_NONNULL(2);
|
||||
|
||||
@@ -130,7 +130,7 @@ extern void *(*MEM_mallocN)(size_t len, const char *str) /* ATTR_MALLOC */ ATTR_
|
||||
* Allocate a block of memory of size (len * size), with tag name str,
|
||||
* aborting in case of integer overflow to prevent vulnerabilities. The
|
||||
* name must be a static, because only a pointer to it is stored !
|
||||
* */
|
||||
*/
|
||||
extern void *(*MEM_malloc_arrayN)(size_t len,
|
||||
size_t size,
|
||||
const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
|
||||
@@ -139,7 +139,7 @@ extern void *(*MEM_malloc_arrayN)(size_t len,
|
||||
/**
|
||||
* Allocate an aligned block of memory of size len, with tag name str. The
|
||||
* name must be a static, because only a pointer to it is stored !
|
||||
* */
|
||||
*/
|
||||
extern void *(*MEM_mallocN_aligned)(size_t len,
|
||||
size_t alignment,
|
||||
const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
|
||||
|
@@ -1,294 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2008 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup MEM
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
# include <errno.h>
|
||||
# include <io.h>
|
||||
# include <stdio.h>
|
||||
# include <sys/types.h>
|
||||
# include <windows.h>
|
||||
|
||||
# include "mmap_win.h"
|
||||
|
||||
# ifndef FILE_MAP_EXECUTE
|
||||
// not defined in earlier versions of the Platform SDK (before February 2003)
|
||||
# define FILE_MAP_EXECUTE 0x0020
|
||||
# endif
|
||||
|
||||
/* copied from BLI_utildefines.h, ugh */
|
||||
# ifdef __GNUC__
|
||||
# define UNUSED(x) UNUSED_##x __attribute__((__unused__))
|
||||
# else
|
||||
# define UNUSED(x) x
|
||||
# endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* local storage definitions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* all memory mapped chunks are put in linked lists */
|
||||
typedef struct mmapLink {
|
||||
struct mmapLink *next, *prev;
|
||||
} mmapLink;
|
||||
|
||||
typedef struct mmapListBase {
|
||||
void *first, *last;
|
||||
} mmapListBase;
|
||||
|
||||
typedef struct MemMap {
|
||||
struct MemMap *next, *prev;
|
||||
void *mmap;
|
||||
HANDLE fhandle;
|
||||
HANDLE maphandle;
|
||||
} MemMap;
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* local functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static void mmap_addtail(volatile mmapListBase *listbase, void *vlink);
|
||||
static void mmap_remlink(volatile mmapListBase *listbase, void *vlink);
|
||||
static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr);
|
||||
|
||||
static int mmap_get_prot_flags(int flags);
|
||||
static int mmap_get_access_flags(int flags);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* vars */
|
||||
/* --------------------------------------------------------------------- */
|
||||
volatile static struct mmapListBase _mmapbase;
|
||||
volatile static struct mmapListBase *mmapbase = &_mmapbase;
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* implementation */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* mmap for windows */
|
||||
void *mmap(void *UNUSED(start), size_t len, int prot, int flags, int fd, off_t offset)
|
||||
{
|
||||
HANDLE fhandle = INVALID_HANDLE_VALUE;
|
||||
HANDLE maphandle;
|
||||
int prot_flags = mmap_get_prot_flags(prot);
|
||||
int access_flags = mmap_get_access_flags(prot);
|
||||
MemMap *mm = NULL;
|
||||
void *ptr = NULL;
|
||||
|
||||
if (flags & MAP_FIXED) {
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
# if 0
|
||||
if (fd == -1) {
|
||||
_set_errno(EBADF);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (fd != -1) {
|
||||
fhandle = (HANDLE)_get_osfhandle(fd);
|
||||
}
|
||||
if (fhandle == INVALID_HANDLE_VALUE) {
|
||||
if (!(flags & MAP_ANONYMOUS)) {
|
||||
errno = EBADF;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!DuplicateHandle(GetCurrentProcess(),
|
||||
fhandle,
|
||||
GetCurrentProcess(),
|
||||
&fhandle,
|
||||
0,
|
||||
FALSE,
|
||||
DUPLICATE_SAME_ACCESS)) {
|
||||
return MAP_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Split 64 bit size into low and high bits. */
|
||||
DWORD len_bits_high = len >> 32;
|
||||
DWORD len_bits_low = len & 0xFFFFFFFF;
|
||||
|
||||
maphandle = CreateFileMapping(fhandle, NULL, prot_flags, len_bits_high, len_bits_low, NULL);
|
||||
if (maphandle == 0) {
|
||||
errno = EBADF;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
ptr = MapViewOfFile(maphandle, access_flags, 0, offset, 0);
|
||||
if (ptr == NULL) {
|
||||
DWORD dwLastErr = GetLastError();
|
||||
if (dwLastErr == ERROR_MAPPED_ALIGNMENT) {
|
||||
errno = EINVAL;
|
||||
}
|
||||
else {
|
||||
errno = EACCES;
|
||||
}
|
||||
CloseHandle(maphandle);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
mm = (MemMap *)malloc(sizeof(MemMap));
|
||||
if (!mm) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
mm->fhandle = fhandle;
|
||||
mm->maphandle = maphandle;
|
||||
mm->mmap = ptr;
|
||||
mmap_addtail(mmapbase, mm);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* munmap for windows */
|
||||
intptr_t munmap(void *ptr, size_t UNUSED(size))
|
||||
{
|
||||
MemMap *mm = mmap_findlink(mmapbase, ptr);
|
||||
if (!mm) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
UnmapViewOfFile(mm->mmap);
|
||||
CloseHandle(mm->maphandle);
|
||||
CloseHandle(mm->fhandle);
|
||||
mmap_remlink(mmapbase, mm);
|
||||
free(mm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* local functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static void mmap_addtail(volatile mmapListBase *listbase, void *vlink)
|
||||
{
|
||||
struct mmapLink *link = vlink;
|
||||
|
||||
if (link == NULL) {
|
||||
return;
|
||||
}
|
||||
if (listbase == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
link->next = 0;
|
||||
link->prev = listbase->last;
|
||||
|
||||
if (listbase->last) {
|
||||
((struct mmapLink *)listbase->last)->next = link;
|
||||
}
|
||||
if (listbase->first == NULL) {
|
||||
listbase->first = link;
|
||||
}
|
||||
listbase->last = link;
|
||||
}
|
||||
|
||||
static void mmap_remlink(volatile mmapListBase *listbase, void *vlink)
|
||||
{
|
||||
struct mmapLink *link = vlink;
|
||||
|
||||
if (link == NULL) {
|
||||
return;
|
||||
}
|
||||
if (listbase == NULL) {
|
||||
return;
|
||||
}
|
||||
if (link->next) {
|
||||
link->next->prev = link->prev;
|
||||
}
|
||||
if (link->prev) {
|
||||
link->prev->next = link->next;
|
||||
}
|
||||
|
||||
if (listbase->last == link) {
|
||||
listbase->last = link->prev;
|
||||
}
|
||||
if (listbase->first == link) {
|
||||
listbase->first = link->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr)
|
||||
{
|
||||
MemMap *mm;
|
||||
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (listbase == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mm = (MemMap *)listbase->first;
|
||||
while (mm) {
|
||||
if (mm->mmap == ptr) {
|
||||
return mm;
|
||||
}
|
||||
mm = mm->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int mmap_get_prot_flags(int flags)
|
||||
{
|
||||
int prot = PAGE_NOACCESS;
|
||||
|
||||
if ((flags & PROT_READ) == PROT_READ) {
|
||||
if ((flags & PROT_WRITE) == PROT_WRITE) {
|
||||
prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
|
||||
}
|
||||
else {
|
||||
prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_READONLY;
|
||||
}
|
||||
}
|
||||
else if ((flags & PROT_WRITE) == PROT_WRITE) {
|
||||
prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_WRITECOPY;
|
||||
}
|
||||
else if ((flags & PROT_EXEC) == PROT_EXEC) {
|
||||
prot = PAGE_EXECUTE_READ;
|
||||
}
|
||||
return prot;
|
||||
}
|
||||
|
||||
static int mmap_get_access_flags(int flags)
|
||||
{
|
||||
int access = 0;
|
||||
|
||||
if ((flags & PROT_READ) == PROT_READ) {
|
||||
if ((flags & PROT_WRITE) == PROT_WRITE) {
|
||||
access = FILE_MAP_WRITE;
|
||||
}
|
||||
else {
|
||||
access = (flags & PROT_EXEC) ? FILE_MAP_EXECUTE : FILE_MAP_READ;
|
||||
}
|
||||
}
|
||||
else if ((flags & PROT_WRITE) == PROT_WRITE) {
|
||||
access = FILE_MAP_COPY;
|
||||
}
|
||||
else if ((flags & PROT_EXEC) == PROT_EXEC) {
|
||||
access = FILE_MAP_EXECUTE;
|
||||
}
|
||||
return access;
|
||||
}
|
||||
|
||||
#endif // WIN32
|
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2008 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup MEM
|
||||
*/
|
||||
|
||||
#ifndef __MMAP_WIN_H__
|
||||
#define __MMAP_WIN_H__
|
||||
|
||||
#define PROT_NONE 0
|
||||
#define PROT_READ 1
|
||||
#define PROT_WRITE 2
|
||||
#define PROT_EXEC 4
|
||||
|
||||
#define MAP_FILE 0
|
||||
#define MAP_SHARED 1
|
||||
#define MAP_PRIVATE 2
|
||||
#define MAP_TYPE 0xF
|
||||
#define MAP_FIXED 0x10
|
||||
#define MAP_ANONYMOUS 0x20
|
||||
#define MAP_ANON MAP_ANONYMOUS
|
||||
|
||||
#define MAP_FAILED ((void *)-1)
|
||||
|
||||
/* needed for uintptr_t, exception, dont use BLI anywhere else in MEM_* */
|
||||
#include "../../source/blender/blenlib/BLI_sys_types.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
void *mmap(void *start, size_t len, int prot, int flags, int fd, off_t offset);
|
||||
intptr_t munmap(void *ptr, size_t size);
|
||||
|
||||
#endif
|
BIN
release/datafiles/icons/brush.sculpt.displacement_smear.dat
Normal file
BIN
release/datafiles/icons/brush.sculpt.displacement_smear.dat
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user