Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mours <pmours@nvidia.com>2022-01-04 23:39:54 +0300
committerPatrick Mours <pmours@nvidia.com>2022-01-05 17:58:36 +0300
commit8393ccd07634b3152b18d4d527b1460dab9dbe06 (patch)
tree816b4dcaa9b8e5163c3934743fe1604f02983e71 /intern/cycles/device
parent86141a75ebc5d0517edf71f2bc2fe7d0d13d8b5e (diff)
Cycles: Add OptiX temporal denoising support
Enables the `bpy.ops.cycles.denoise_animation()` operator again and modifies it to support temporal denoising with OptiX. This requires renders that were done with both the "Vector" and "Denoising Data" passes. Differential Revision: https://developer.blender.org/D11442
Diffstat (limited to 'intern/cycles/device')
-rw-r--r--intern/cycles/device/denoise.cpp2
-rw-r--r--intern/cycles/device/denoise.h6
-rw-r--r--intern/cycles/device/optix/device_impl.cpp81
-rw-r--r--intern/cycles/device/optix/device_impl.h1
-rw-r--r--intern/cycles/device/queue.h5
5 files changed, 86 insertions, 9 deletions
diff --git a/intern/cycles/device/denoise.cpp b/intern/cycles/device/denoise.cpp
index c291a7a0adb..8ae2bb213e4 100644
--- a/intern/cycles/device/denoise.cpp
+++ b/intern/cycles/device/denoise.cpp
@@ -76,6 +76,8 @@ NODE_DEFINE(DenoiseParams)
SOCKET_BOOLEAN(use_pass_albedo, "Use Pass Albedo", true);
SOCKET_BOOLEAN(use_pass_normal, "Use Pass Normal", false);
+ SOCKET_BOOLEAN(temporally_stable, "Temporally Stable", false);
+
SOCKET_ENUM(prefilter, "Prefilter", *prefilter_enum, DENOISER_PREFILTER_FAST);
return type;
diff --git a/intern/cycles/device/denoise.h b/intern/cycles/device/denoise.h
index 3f30506ae06..07868527fc5 100644
--- a/intern/cycles/device/denoise.h
+++ b/intern/cycles/device/denoise.h
@@ -72,6 +72,9 @@ class DenoiseParams : public Node {
bool use_pass_albedo = true;
bool use_pass_normal = true;
+ /* Configure the denoiser to use motion vectors, previous image and a temporally stable model. */
+ bool temporally_stable = false;
+
DenoiserPrefilter prefilter = DENOISER_PREFILTER_FAST;
static const NodeEnum *get_type_enum();
@@ -83,7 +86,8 @@ class DenoiseParams : public Node {
{
return !(use == other.use && type == other.type && start_sample == other.start_sample &&
use_pass_albedo == other.use_pass_albedo &&
- use_pass_normal == other.use_pass_normal && prefilter == other.prefilter);
+ use_pass_normal == other.use_pass_normal &&
+ temporally_stable == other.temporally_stable && prefilter == other.prefilter);
}
};
diff --git a/intern/cycles/device/optix/device_impl.cpp b/intern/cycles/device/optix/device_impl.cpp
index 38cc3330ebd..009661b2dec 100644
--- a/intern/cycles/device/optix/device_impl.cpp
+++ b/intern/cycles/device/optix/device_impl.cpp
@@ -566,6 +566,19 @@ class OptiXDevice::DenoiseContext {
}
}
+ if (denoise_params.temporally_stable) {
+ prev_output.device_pointer = render_buffers->buffer.device_pointer;
+
+ prev_output.offset = buffer_params.get_pass_offset(PASS_DENOISING_PREVIOUS);
+
+ prev_output.stride = buffer_params.stride;
+ prev_output.pass_stride = buffer_params.pass_stride;
+
+ num_input_passes += 1;
+ use_pass_flow = true;
+ pass_motion = buffer_params.get_pass_offset(PASS_MOTION);
+ }
+
use_guiding_passes = (num_input_passes - 1) > 0;
if (use_guiding_passes) {
@@ -574,6 +587,7 @@ class OptiXDevice::DenoiseContext {
guiding_params.pass_albedo = pass_denoising_albedo;
guiding_params.pass_normal = pass_denoising_normal;
+ guiding_params.pass_flow = pass_motion;
guiding_params.stride = buffer_params.stride;
guiding_params.pass_stride = buffer_params.pass_stride;
@@ -588,6 +602,10 @@ class OptiXDevice::DenoiseContext {
guiding_params.pass_normal = guiding_params.pass_stride;
guiding_params.pass_stride += 3;
}
+ if (use_pass_flow) {
+ guiding_params.pass_flow = guiding_params.pass_stride;
+ guiding_params.pass_stride += 2;
+ }
guiding_params.stride = buffer_params.width;
@@ -605,6 +623,16 @@ class OptiXDevice::DenoiseContext {
RenderBuffers *render_buffers = nullptr;
const BufferParams &buffer_params;
+ /* Previous output. */
+ struct {
+ device_ptr device_pointer = 0;
+
+ int offset = PASS_UNUSED;
+
+ int stride = -1;
+ int pass_stride = -1;
+ } prev_output;
+
/* Device-side storage of the guiding passes. */
device_only_memory<float> guiding_buffer;
@@ -614,6 +642,7 @@ class OptiXDevice::DenoiseContext {
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_albedo = PASS_UNUSED;
int pass_normal = PASS_UNUSED;
+ int pass_flow = PASS_UNUSED;
int stride = -1;
int pass_stride = -1;
@@ -624,6 +653,7 @@ class OptiXDevice::DenoiseContext {
bool use_guiding_passes = false;
bool use_pass_albedo = false;
bool use_pass_normal = false;
+ bool use_pass_flow = false;
int num_samples = 0;
@@ -632,6 +662,7 @@ class OptiXDevice::DenoiseContext {
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_denoising_albedo = PASS_UNUSED;
int pass_denoising_normal = PASS_UNUSED;
+ int pass_motion = PASS_UNUSED;
/* For passes which don't need albedo channel for denoising we replace the actual albedo with
* the (0.5, 0.5, 0.5). This flag indicates that the real albedo pass has been replaced with
@@ -702,6 +733,7 @@ bool OptiXDevice::denoise_filter_guiding_preprocess(DenoiseContext &context)
&context.guiding_params.pass_stride,
&context.guiding_params.pass_albedo,
&context.guiding_params.pass_normal,
+ &context.guiding_params.pass_flow,
&context.render_buffers->buffer.device_pointer,
&buffer_params.offset,
&buffer_params.stride,
@@ -709,6 +741,7 @@ bool OptiXDevice::denoise_filter_guiding_preprocess(DenoiseContext &context)
&context.pass_sample_count,
&context.pass_denoising_albedo,
&context.pass_denoising_normal,
+ &context.pass_motion,
&buffer_params.full_x,
&buffer_params.full_y,
&buffer_params.width,
@@ -881,7 +914,8 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context)
{
const bool recreate_denoiser = (denoiser_.optix_denoiser == nullptr) ||
(denoiser_.use_pass_albedo != context.use_pass_albedo) ||
- (denoiser_.use_pass_normal != context.use_pass_normal);
+ (denoiser_.use_pass_normal != context.use_pass_normal) ||
+ (denoiser_.use_pass_flow != context.use_pass_flow);
if (!recreate_denoiser) {
return true;
}
@@ -895,8 +929,14 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context)
OptixDenoiserOptions denoiser_options = {};
denoiser_options.guideAlbedo = context.use_pass_albedo;
denoiser_options.guideNormal = context.use_pass_normal;
+
+ OptixDenoiserModelKind model = OPTIX_DENOISER_MODEL_KIND_HDR;
+ if (context.use_pass_flow) {
+ model = OPTIX_DENOISER_MODEL_KIND_TEMPORAL;
+ }
+
const OptixResult result = optixDenoiserCreate(
- this->context, OPTIX_DENOISER_MODEL_KIND_HDR, &denoiser_options, &denoiser_.optix_denoiser);
+ this->context, model, &denoiser_options, &denoiser_.optix_denoiser);
if (result != OPTIX_SUCCESS) {
set_error("Failed to create OptiX denoiser");
@@ -906,6 +946,7 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context)
/* OptiX denoiser handle was created with the requested number of input passes. */
denoiser_.use_pass_albedo = context.use_pass_albedo;
denoiser_.use_pass_normal = context.use_pass_normal;
+ denoiser_.use_pass_flow = context.use_pass_flow;
/* OptiX denoiser has been created, but it needs configuration. */
denoiser_.is_configured = false;
@@ -965,8 +1006,10 @@ bool OptiXDevice::denoise_run(DenoiseContext &context, const DenoisePass &pass)
OptixImage2D color_layer = {0};
OptixImage2D albedo_layer = {0};
OptixImage2D normal_layer = {0};
+ OptixImage2D flow_layer = {0};
OptixImage2D output_layer = {0};
+ OptixImage2D prev_output_layer = {0};
/* Color pass. */
{
@@ -982,6 +1025,19 @@ bool OptiXDevice::denoise_run(DenoiseContext &context, const DenoisePass &pass)
color_layer.format = OPTIX_PIXEL_FORMAT_FLOAT3;
}
+ /* Previous output. */
+ if (context.prev_output.offset != PASS_UNUSED) {
+ const int64_t pass_stride_in_bytes = context.prev_output.pass_stride * sizeof(float);
+
+ prev_output_layer.data = context.prev_output.device_pointer +
+ context.prev_output.offset * sizeof(float);
+ prev_output_layer.width = width;
+ prev_output_layer.height = height;
+ prev_output_layer.rowStrideInBytes = pass_stride_in_bytes * context.prev_output.stride;
+ prev_output_layer.pixelStrideInBytes = pass_stride_in_bytes;
+ prev_output_layer.format = OPTIX_PIXEL_FORMAT_FLOAT3;
+ }
+
/* Optional albedo and color passes. */
if (context.num_input_passes > 1) {
const device_ptr d_guiding_buffer = context.guiding_params.device_pointer;
@@ -1005,21 +1061,32 @@ bool OptiXDevice::denoise_run(DenoiseContext &context, const DenoisePass &pass)
normal_layer.pixelStrideInBytes = pixel_stride_in_bytes;
normal_layer.format = OPTIX_PIXEL_FORMAT_FLOAT3;
}
+
+ if (context.use_pass_flow) {
+ flow_layer.data = d_guiding_buffer + context.guiding_params.pass_flow * sizeof(float);
+ flow_layer.width = width;
+ flow_layer.height = height;
+ flow_layer.rowStrideInBytes = row_stride_in_bytes;
+ flow_layer.pixelStrideInBytes = pixel_stride_in_bytes;
+ flow_layer.format = OPTIX_PIXEL_FORMAT_FLOAT2;
+ }
}
/* Denoise in-place of the noisy input in the render buffers. */
output_layer = color_layer;
- /* Finally run denoising. */
- OptixDenoiserParams params = {}; /* All parameters are disabled/zero. */
+ OptixDenoiserGuideLayer guide_layers = {};
+ guide_layers.albedo = albedo_layer;
+ guide_layers.normal = normal_layer;
+ guide_layers.flow = flow_layer;
OptixDenoiserLayer image_layers = {};
image_layers.input = color_layer;
+ image_layers.previousOutput = prev_output_layer;
image_layers.output = output_layer;
- OptixDenoiserGuideLayer guide_layers = {};
- guide_layers.albedo = albedo_layer;
- guide_layers.normal = normal_layer;
+ /* Finally run denoising. */
+ OptixDenoiserParams params = {}; /* All parameters are disabled/zero. */
optix_assert(optixUtilDenoiserInvokeTiled(denoiser_.optix_denoiser,
denoiser_.queue.stream(),
diff --git a/intern/cycles/device/optix/device_impl.h b/intern/cycles/device/optix/device_impl.h
index 25073c60e69..a1865527c2d 100644
--- a/intern/cycles/device/optix/device_impl.h
+++ b/intern/cycles/device/optix/device_impl.h
@@ -104,6 +104,7 @@ class OptiXDevice : public CUDADevice {
bool use_pass_albedo = false;
bool use_pass_normal = false;
+ bool use_pass_flow = false;
};
Denoiser denoiser_;
diff --git a/intern/cycles/device/queue.h b/intern/cycles/device/queue.h
index 4e9f41f7875..926b7cba78a 100644
--- a/intern/cycles/device/queue.h
+++ b/intern/cycles/device/queue.h
@@ -19,6 +19,7 @@
#include "device/kernel.h"
#include "device/graphics_interop.h"
+#include "util/debug.h"
#include "util/log.h"
#include "util/map.h"
#include "util/string.h"
@@ -42,7 +43,7 @@ struct DeviceKernelArguments {
KERNEL_FILM_CONVERT,
};
- static const int MAX_ARGS = 16;
+ static const int MAX_ARGS = 18;
Type types[MAX_ARGS];
void *values[MAX_ARGS];
size_t sizes[MAX_ARGS];
@@ -85,6 +86,8 @@ struct DeviceKernelArguments {
}
void add(const Type type, const void *value, size_t size)
{
+ assert(count < MAX_ARGS);
+
types[count] = type;
values[count] = (void *)value;
sizes[count] = size;