168 lines
6.0 KiB
C++
168 lines
6.0 KiB
C++
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
|
|
|
#pragma once
|
|
|
|
#include "integrator/denoiser.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
/* Implementation of Denoiser which uses a device-specific denoising implementation, running on a
|
|
* GPU device queue. It makes sure the to-be-denoised buffer is available on the denoising device
|
|
* and invokes denoising kernels via the device queue API. */
|
|
class DenoiserGPU : public Denoiser {
|
|
public:
|
|
DenoiserGPU(Device *path_trace_device, const DenoiseParams ¶ms);
|
|
~DenoiserGPU();
|
|
|
|
virtual bool denoise_buffer(const BufferParams &buffer_params,
|
|
RenderBuffers *render_buffers,
|
|
const int num_samples,
|
|
bool allow_inplace_modification) override;
|
|
|
|
protected:
|
|
class DenoisePass;
|
|
class DenoiseContext;
|
|
|
|
/* All the parameters needed to perform buffer denoising on a device.
|
|
* Is not really a task in its canonical terms (as in, is not an asynchronous running task). Is
|
|
* more like a wrapper for all the arguments and parameters needed to perform denoising. Is a
|
|
* single place where they are all listed, so that it's not required to modify all device methods
|
|
* when these parameters do change. */
|
|
class DenoiseTask {
|
|
public:
|
|
DenoiseParams params;
|
|
|
|
int num_samples;
|
|
|
|
RenderBuffers *render_buffers;
|
|
BufferParams buffer_params;
|
|
|
|
/* Allow to do in-place modification of the input passes (scaling them down i.e.). This will
|
|
* lower the memory footprint of the denoiser but will make input passes "invalid" (from path
|
|
* tracer) point of view. */
|
|
bool allow_inplace_modification;
|
|
};
|
|
|
|
/* Make sure the GPU denoiser is created and configured. */
|
|
virtual bool denoise_ensure(DenoiseContext &context);
|
|
|
|
/* Create GPU denoiser descriptor if needed.
|
|
* Will do nothing if the current GPU descriptor is usable for the given parameters.
|
|
* If the GPU denoiser descriptor did re-allocate here it is left unconfigured. */
|
|
virtual bool denoise_create_if_needed(DenoiseContext &context) = 0;
|
|
|
|
/* Configure existing GPU denoiser descriptor for the use for the given task. */
|
|
virtual bool denoise_configure_if_needed(DenoiseContext &context) = 0;
|
|
|
|
/* Read input color pass from the render buffer into the memory which corresponds to the noisy
|
|
* input within the given context. Pixels are scaled to the number of samples, but are not
|
|
* preprocessed yet. */
|
|
void denoise_color_read(const DenoiseContext &context, const DenoisePass &pass);
|
|
|
|
/* Run corresponding filter kernels, preparing data for the denoiser or copying data from the
|
|
* denoiser result to the render buffer. */
|
|
bool denoise_filter_color_preprocess(const DenoiseContext &context, const DenoisePass &pass);
|
|
bool denoise_filter_color_postprocess(const DenoiseContext &context, const DenoisePass &pass);
|
|
bool denoise_filter_guiding_set_fake_albedo(const DenoiseContext &context);
|
|
|
|
/* Read guiding passes from the render buffers, preprocess them in a way which is expected by
|
|
* the GPU denoiser and store in the guiding passes memory within the given context.
|
|
*
|
|
* Pre-processing of the guiding passes is to only happen once per context lifetime. DO not
|
|
* preprocess them for every pass which is being denoised. */
|
|
bool denoise_filter_guiding_preprocess(const DenoiseContext &context);
|
|
|
|
void denoise_pass(DenoiseContext &context, PassType pass_type);
|
|
|
|
/* Returns true if task is fully handled. */
|
|
virtual bool denoise_buffer(const DenoiseTask &task);
|
|
virtual bool denoise_run(const DenoiseContext &context, const DenoisePass &pass) = 0;
|
|
|
|
virtual Device *ensure_denoiser_device(Progress *progress) override;
|
|
|
|
unique_ptr<DeviceQueue> denoiser_queue_;
|
|
|
|
class DenoisePass {
|
|
public:
|
|
DenoisePass(const PassType type, const BufferParams &buffer_params) : type(type)
|
|
{
|
|
noisy_offset = buffer_params.get_pass_offset(type, PassMode::NOISY);
|
|
denoised_offset = buffer_params.get_pass_offset(type, PassMode::DENOISED);
|
|
|
|
const PassInfo pass_info = Pass::get_info(type);
|
|
num_components = pass_info.num_components;
|
|
use_compositing = pass_info.use_compositing;
|
|
use_denoising_albedo = pass_info.use_denoising_albedo;
|
|
}
|
|
|
|
PassType type;
|
|
|
|
int noisy_offset;
|
|
int denoised_offset;
|
|
|
|
int num_components;
|
|
int use_compositing;
|
|
bool use_denoising_albedo;
|
|
};
|
|
|
|
class DenoiseContext {
|
|
public:
|
|
explicit DenoiseContext(Device *device, const DenoiseTask &task);
|
|
|
|
const DenoiseParams &denoise_params;
|
|
|
|
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;
|
|
|
|
struct {
|
|
device_ptr device_pointer = 0;
|
|
|
|
/* 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;
|
|
} guiding_params;
|
|
|
|
/* Number of input passes. Including the color and extra auxiliary passes. */
|
|
int num_input_passes = 0;
|
|
bool use_guiding_passes = false;
|
|
bool use_pass_albedo = false;
|
|
bool use_pass_normal = false;
|
|
bool use_pass_motion = false;
|
|
|
|
int num_samples = 0;
|
|
|
|
int pass_sample_count = PASS_UNUSED;
|
|
|
|
/* 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
|
|
* the fake values and denoising of passes which do need albedo can no longer happen. */
|
|
bool albedo_replaced_with_fake = false;
|
|
};
|
|
};
|
|
|
|
CCL_NAMESPACE_END
|