Cycles: More accurate volume stack size calculation

The idea is to allow having a lot of non-intersecting volumes without
allocating volume stack to its full size.

With the F11285472 file the memory usage goes from 1400 MiB to 1000
on the RTX6000 card.

The fix makes it so the integrator work memory is allocated after
scene update which has downside of possible less efficient update
when some textures don't fit GPU memory, but has an advantage of
making proper decision and having a clear and consistent internal API.

Fixes memory part of T92014.

Differential Revision: https://developer.blender.org/D12966
This commit is contained in:
Sergey Sharybin
2021-10-22 14:20:22 +02:00
parent 8733d310e5
commit c4fa17c67a
5 changed files with 31 additions and 36 deletions

View File

@@ -360,6 +360,8 @@ void Scene::device_update(Device *device_, Progress &progress)
return;
if (device->have_error() == false) {
dscene.data.volume_stack_size = get_volume_stack_size();
progress.set_status("Updating Device", "Writing constant memory");
device->const_copy_to("__data", &dscene.data, sizeof(dscene.data));
}
@@ -527,8 +529,6 @@ void Scene::update_kernel_features()
const uint max_closures = (params.background) ? get_max_closure_count() : MAX_CLOSURE;
dscene.data.max_closures = max_closures;
dscene.data.max_shaders = shaders.size();
dscene.data.volume_stack_size = get_volume_stack_size();
}
bool Scene::update(Progress &progress)
@@ -586,6 +586,8 @@ bool Scene::load_kernels(Progress &progress, bool lock_scene)
scene_lock = thread_scoped_lock(mutex);
}
update_kernel_features();
const uint kernel_features = dscene.data.kernel_features;
if (!kernels_loaded || loaded_kernel_features != kernel_features) {
@@ -656,10 +658,25 @@ int Scene::get_volume_stack_size() const
/* Quick non-expensive check. Can over-estimate maximum possible nested level, but does not
* require expensive calculation during pre-processing. */
bool has_volume_object = false;
for (const Object *object : objects) {
if (object->check_is_volume()) {
if (!object->get_geometry()->has_volume) {
continue;
}
if (object->intersects_volume) {
/* Object intersects another volume, assume it's possible to go deeper in the stack. */
/* TODO(sergey): This might count nesting twice (A intersects B and B intersects A), but
* can't think of a computantially cheap algorithm. Dividing my 2 doesn't work because of
* Venn diagram example with 3 circles. */
++volume_stack_size;
}
else if (!has_volume_object) {
/* Allocate space for at least one volume object. */
++volume_stack_size;
}
has_volume_object = true;
if (volume_stack_size == MAX_VOLUME_STACK_SIZE) {
break;
@@ -668,6 +685,8 @@ int Scene::get_volume_stack_size() const
volume_stack_size = min(volume_stack_size, MAX_VOLUME_STACK_SIZE);
VLOG(3) << "Detected required volume stack size " << volume_stack_size;
return volume_stack_size;
}