diff options
author | Brecht Van Lommel <brecht@blender.org> | 2020-06-01 00:49:10 +0300 |
---|---|---|
committer | Brecht Van Lommel <brecht@blender.org> | 2020-06-24 16:17:36 +0300 |
commit | 0a3bde63006c66b8b8531ed5eccca9bdf5e5dc20 (patch) | |
tree | cf4a577e1fb0cfdaf0c47d56879ae49a21b68c1d /intern/cycles/device | |
parent | 88157b9efb2027380c4083d06e4ed61d8d109cef (diff) |
Cycles: add denoising settings to the render properties
Enabling render and viewport denoising is now both done from the render
properties. View layers still can individually be enabled/disabled for
denoising and have their own denoising parameters.
Note that the denoising engine also affects how denoising data passes are
output even if no denoising happens on the render itself, to make the passes
compatible with the engine.
This includes internal refactoring for how denoising parameters are passed
along, trying to avoid code duplication and unclear naming.
Ref T76259
Diffstat (limited to 'intern/cycles/device')
-rw-r--r-- | intern/cycles/device/device.cpp | 41 | ||||
-rw-r--r-- | intern/cycles/device/device.h | 5 | ||||
-rw-r--r-- | intern/cycles/device/device_cpu.cpp | 19 | ||||
-rw-r--r-- | intern/cycles/device/device_cuda.cpp | 1 | ||||
-rw-r--r-- | intern/cycles/device/device_denoising.cpp | 10 | ||||
-rw-r--r-- | intern/cycles/device/device_denoising.h | 2 | ||||
-rw-r--r-- | intern/cycles/device/device_network.cpp | 1 | ||||
-rw-r--r-- | intern/cycles/device/device_opencl.cpp | 1 | ||||
-rw-r--r-- | intern/cycles/device/device_optix.cpp | 3 | ||||
-rw-r--r-- | intern/cycles/device/device_task.h | 45 |
10 files changed, 113 insertions, 15 deletions
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index 263d3d24b13..73415d5f9c6 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -603,6 +603,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices, info.has_osl = true; info.has_profiling = true; info.has_peer_memory = false; + info.denoisers = DENOISER_ALL; foreach (const DeviceInfo &device, subdevices) { /* Ensure CPU device does not slow down GPU. */ @@ -647,6 +648,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices, info.has_osl &= device.has_osl; info.has_profiling &= device.has_profiling; info.has_peer_memory |= device.has_peer_memory; + info.denoisers &= device.denoisers; } return info; @@ -667,4 +669,43 @@ void Device::free_memory() network_devices.free_memory(); } +/* DeviceInfo */ + +void DeviceInfo::add_denoising_devices(DenoiserType denoiser_type) +{ + assert(denoising_devices.empty()); + + if (denoiser_type == DENOISER_OPTIX && type != DEVICE_OPTIX) { + vector<DeviceInfo> optix_devices = Device::available_devices(DEVICE_MASK_OPTIX); + if (!optix_devices.empty()) { + /* Convert to a special multi device with separate denoising devices. */ + if (multi_devices.empty()) { + multi_devices.push_back(*this); + } + + /* Try to use the same physical devices for denoising. */ + for (const DeviceInfo &cuda_device : multi_devices) { + if (cuda_device.type == DEVICE_CUDA) { + for (const DeviceInfo &optix_device : optix_devices) { + if (cuda_device.num == optix_device.num) { + id += optix_device.id; + denoising_devices.push_back(optix_device); + break; + } + } + } + } + + if (denoising_devices.empty()) { + /* Simply use the first available OptiX device. */ + const DeviceInfo optix_device = optix_devices.front(); + id += optix_device.id; /* Uniquely identify this special multi device. */ + denoising_devices.push_back(optix_device); + } + + denoisers = denoiser_type; + } + } +} + CCL_NAMESPACE_END diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 69f22aeb35c..a5833369a17 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -83,6 +83,7 @@ class DeviceInfo { bool use_split_kernel; /* Use split or mega kernel. */ bool has_profiling; /* Supports runtime collection of profiling info. */ bool has_peer_memory; /* GPU has P2P access to memory of another GPU. */ + DenoiserTypeMask denoisers; /* Supported denoiser types. */ int cpu_threads; vector<DeviceInfo> multi_devices; vector<DeviceInfo> denoising_devices; @@ -101,6 +102,7 @@ class DeviceInfo { use_split_kernel = false; has_profiling = false; has_peer_memory = false; + denoisers = DENOISER_NONE; } bool operator==(const DeviceInfo &info) @@ -110,6 +112,9 @@ class DeviceInfo { (type == info.type && num == info.num && description == info.description)); return id == info.id; } + + /* Add additional devices needed for the specified denoiser. */ + void add_denoising_devices(DenoiserType denoiser_type); }; class DeviceRequestedFeatures { diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index a36c76c852a..1f760a15530 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -943,7 +943,7 @@ class CPUDevice : public Device { } } - void denoise(DenoisingTask &denoising, RenderTile &tile) + void denoise_nlm(DenoisingTask &denoising, RenderTile &tile) { ProfilingHelper profiling(denoising.profiler, PROFILING_DENOISING); @@ -1001,10 +1001,9 @@ class CPUDevice : public Device { } } - RenderTile tile; - DenoisingTask denoising(this, task); - denoising.profiler = &kg->profiler; + DenoisingTask *denoising = NULL; + RenderTile tile; while (task.acquire_tile(this, tile, task.tile_types)) { if (tile.task == RenderTile::PATH_TRACE) { if (use_split_kernel) { @@ -1019,7 +1018,13 @@ class CPUDevice : public Device { render(task, tile, kg); } else if (tile.task == RenderTile::DENOISE) { - denoise(denoising, tile); + if (task.denoising.type == DENOISER_NLM) { + if (denoising == NULL) { + denoising = new DenoisingTask(this, task); + denoising->profiler = &kg->profiler; + } + denoise_nlm(*denoising, tile); + } task.update_progress(&tile, tile.w * tile.h); } @@ -1037,6 +1042,7 @@ class CPUDevice : public Device { kg->~KernelGlobals(); kgbuffer.free(); delete split_kernel; + delete denoising; } void thread_denoise(DeviceTask &task) @@ -1060,7 +1066,7 @@ class CPUDevice : public Device { profiler.add_state(&denoising_profiler_state); denoising.profiler = &denoising_profiler_state; - denoise(denoising, tile); + denoise_nlm(denoising, tile); task.update_progress(&tile, tile.w * tile.h); profiler.remove_state(&denoising_profiler_state); @@ -1344,6 +1350,7 @@ void device_cpu_info(vector<DeviceInfo> &devices) info.has_osl = true; info.has_half_images = true; info.has_profiling = true; + info.denoisers = DENOISER_NLM; devices.insert(devices.begin(), info); } diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 04c04761311..d9ffcceb06e 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -130,6 +130,7 @@ void device_cuda_info(vector<DeviceInfo> &devices) info.has_half_images = (major >= 3); info.has_volume_decoupled = false; info.has_adaptive_stop_per_sample = false; + info.denoisers = DENOISER_NLM; /* Check if the device has P2P access to any other device in the system. */ for (int peer_num = 0; peer_num < count && !info.has_peer_memory; peer_num++) { diff --git a/intern/cycles/device/device_denoising.cpp b/intern/cycles/device/device_denoising.cpp index ac17c02a427..91ebb7c266e 100644 --- a/intern/cycles/device/device_denoising.cpp +++ b/intern/cycles/device/device_denoising.cpp @@ -56,8 +56,8 @@ DenoisingTask::DenoisingTask(Device *device, const DeviceTask &task) tile_info->frames[i] = task.denoising_frames[i - 1]; } - write_passes = task.denoising_write_passes; - do_filter = task.denoising_do_filter; + do_prefilter = task.denoising.store_passes && task.denoising.type == DENOISER_NLM; + do_filter = task.denoising_do_filter && task.denoising.type == DENOISER_NLM; } DenoisingTask::~DenoisingTask() @@ -91,7 +91,7 @@ void DenoisingTask::set_render_buffer(RenderTile *rtiles) target_buffer.stride = rtiles[9].stride; target_buffer.ptr = rtiles[9].buffer; - if (write_passes && rtiles[9].buffers) { + if (do_prefilter && rtiles[9].buffers) { target_buffer.denoising_output_offset = rtiles[9].buffers->params.get_denoising_prefiltered_offset(); } @@ -111,7 +111,7 @@ void DenoisingTask::setup_denoising_buffer() rect = rect_clip(rect, make_int4(tile_info->x[0], tile_info->y[0], tile_info->x[3], tile_info->y[3])); - buffer.use_intensity = write_passes || (tile_info->num_frames > 1); + buffer.use_intensity = do_prefilter || (tile_info->num_frames > 1); buffer.passes = buffer.use_intensity ? 15 : 14; buffer.width = rect.z - rect.x; buffer.stride = align_up(buffer.width, 4); @@ -343,7 +343,7 @@ void DenoisingTask::run_denoising(RenderTile *tile) reconstruct(); } - if (write_passes) { + if (do_prefilter) { write_buffer(); } diff --git a/intern/cycles/device/device_denoising.h b/intern/cycles/device/device_denoising.h index bd1d0193dbd..4c122e981eb 100644 --- a/intern/cycles/device/device_denoising.h +++ b/intern/cycles/device/device_denoising.h @@ -60,7 +60,7 @@ class DenoisingTask { int4 rect; int4 filter_area; - bool write_passes; + bool do_prefilter; bool do_filter; struct DeviceFunctions { diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp index 0933d51f321..8904b517e92 100644 --- a/intern/cycles/device/device_network.cpp +++ b/intern/cycles/device/device_network.cpp @@ -313,6 +313,7 @@ void device_network_info(vector<DeviceInfo> &devices) info.has_volume_decoupled = false; info.has_adaptive_stop_per_sample = false; info.has_osl = false; + info.denoisers = DENOISER_NONE; devices.push_back(info); } diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index 8a0b128697f..39b9ef70192 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -120,6 +120,7 @@ void device_opencl_info(vector<DeviceInfo> &devices) info.use_split_kernel = true; info.has_volume_decoupled = false; info.has_adaptive_stop_per_sample = false; + info.denoisers = DENOISER_NLM; info.id = id; /* Check OpenCL extensions */ diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp index 7aab2c96db4..d4d859e8593 100644 --- a/intern/cycles/device/device_optix.cpp +++ b/intern/cycles/device/device_optix.cpp @@ -721,7 +721,7 @@ class OptiXDevice : public CUDADevice { const CUDAContextScope scope(cuContext); // Choose between OptiX and NLM denoising - if (task.denoising_use_optix) { + if (task.denoising.type == DENOISER_OPTIX) { // Map neighboring tiles onto this device, indices are as following: // Where index 4 is the center tile and index 9 is the target for the result. // 0 1 2 @@ -1561,6 +1561,7 @@ void device_optix_info(const vector<DeviceInfo> &cuda_devices, vector<DeviceInfo info.type = DEVICE_OPTIX; info.id += "_OptiX"; + info.denoisers |= DENOISER_OPTIX; devices.push_back(info); } diff --git a/intern/cycles/device/device_task.h b/intern/cycles/device/device_task.h index 5f675bf7e04..1ad8e0d9485 100644 --- a/intern/cycles/device/device_task.h +++ b/intern/cycles/device/device_task.h @@ -31,8 +31,32 @@ class RenderBuffers; class RenderTile; class Tile; +enum DenoiserType { + DENOISER_NLM = 1, + DENOISER_OPTIX = 2, + DENOISER_NUM, + + DENOISER_NONE = 0, + DENOISER_ALL = ~0, +}; + +typedef int DenoiserTypeMask; + class DenoiseParams { public: + /* Apply denoiser to image. */ + bool use; + /* Output denoising data passes (possibly without applying the denoiser). */ + bool store_passes; + + /* Denoiser type. */ + DenoiserType type; + + /* Viewport start sample. */ + int start_sample; + + /** Native Denoiser **/ + /* Pixel radius for neighboring pixels to take into account. */ int radius; /* Controls neighbor pixel weighting for the denoising filter. */ @@ -46,18 +70,36 @@ class DenoiseParams { int neighbor_frames; /* Clamp the input to the range of +-1e8. Should be enough for any legitimate data. */ bool clamp_input; + + /** Optix Denoiser **/ + /* Passes handed over to the OptiX denoiser (default to color + albedo). */ int optix_input_passes; DenoiseParams() { + use = false; + store_passes = false; + + type = DENOISER_NLM; + radius = 8; strength = 0.5f; feature_strength = 0.5f; relative_pca = false; neighbor_frames = 2; clamp_input = true; + optix_input_passes = 2; + + start_sample = 0; + } + + /* Test if a denoising task needs to run, also to prefilter passes for the native + * denoiser when we are not applying denoising to the combined image. */ + bool need_denoising_task() const + { + return (use || (store_passes && type == DENOISER_NLM)); } }; @@ -116,8 +158,7 @@ class DeviceTask { vector<int> denoising_frames; bool denoising_do_filter; - bool denoising_use_optix; - bool denoising_write_passes; + bool denoising_do_prefilter; int pass_stride; int frame_stride; |