Cycles: GPU denoising refactor
Moved more generic code from OptiX to GPU denoiser in order to reuse it for OIDN GPU support. Pull Request: https://projects.blender.org/blender/blender/pulls/112229
This commit is contained in:
@@ -90,6 +90,72 @@ bool DenoiserGPU::denoise_buffer(const BufferParams &buffer_params,
|
||||
return denoise_result;
|
||||
}
|
||||
|
||||
bool DenoiserGPU::denoise_buffer(const DenoiseTask &task)
|
||||
{
|
||||
DenoiseContext context(denoiser_device_, task);
|
||||
|
||||
if (!denoise_ensure(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!denoise_filter_guiding_preprocess(context)) {
|
||||
LOG(ERROR) << "Error preprocessing guiding passes.";
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Passes which will use real albedo when it is available. */
|
||||
denoise_pass(context, PASS_COMBINED);
|
||||
denoise_pass(context, PASS_SHADOW_CATCHER_MATTE);
|
||||
|
||||
/* Passes which do not need albedo and hence if real is present it needs to become fake. */
|
||||
denoise_pass(context, PASS_SHADOW_CATCHER);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DenoiserGPU::denoise_ensure(DenoiseContext &context)
|
||||
{
|
||||
if (!denoise_create_if_needed(context)) {
|
||||
LOG(ERROR) << "GPU denoiser creation has failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!denoise_configure_if_needed(context)) {
|
||||
LOG(ERROR) << "GPU denoiser configuration has failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DenoiserGPU::denoise_filter_guiding_preprocess(const DenoiseContext &context)
|
||||
{
|
||||
const BufferParams &buffer_params = context.buffer_params;
|
||||
|
||||
const int work_size = buffer_params.width * buffer_params.height;
|
||||
|
||||
DeviceKernelArguments args(&context.guiding_params.device_pointer,
|
||||
&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,
|
||||
&buffer_params.pass_stride,
|
||||
&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,
|
||||
&buffer_params.height,
|
||||
&context.num_samples);
|
||||
|
||||
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_GUIDING_PREPROCESS, work_size, args);
|
||||
}
|
||||
|
||||
Device *DenoiserGPU::ensure_denoiser_device(Progress *progress)
|
||||
{
|
||||
Device *denoiser_device = Denoiser::ensure_denoiser_device(progress);
|
||||
|
||||
@@ -45,6 +45,17 @@ class DenoiserGPU : public Denoiser {
|
||||
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. */
|
||||
@@ -56,10 +67,17 @@ class DenoiserGPU : public Denoiser {
|
||||
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*/) = 0;
|
||||
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;
|
||||
|
||||
@@ -225,68 +225,7 @@ bool OptiXDenoiser::denoise_buffer(const DenoiseTask &task)
|
||||
|
||||
const CUDAContextScope scope(optix_device);
|
||||
|
||||
DenoiseContext context(optix_device, task);
|
||||
|
||||
if (!denoise_ensure(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!denoise_filter_guiding_preprocess(context)) {
|
||||
LOG(ERROR) << "Error preprocessing guiding passes.";
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Passes which will use real albedo when it is available. */
|
||||
denoise_pass(context, PASS_COMBINED);
|
||||
denoise_pass(context, PASS_SHADOW_CATCHER_MATTE);
|
||||
|
||||
/* Passes which do not need albedo and hence if real is present it needs to become fake. */
|
||||
denoise_pass(context, PASS_SHADOW_CATCHER);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OptiXDenoiser::denoise_filter_guiding_preprocess(const DenoiseContext &context)
|
||||
{
|
||||
const BufferParams &buffer_params = context.buffer_params;
|
||||
|
||||
const int work_size = buffer_params.width * buffer_params.height;
|
||||
|
||||
DeviceKernelArguments args(&context.guiding_params.device_pointer,
|
||||
&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,
|
||||
&buffer_params.pass_stride,
|
||||
&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,
|
||||
&buffer_params.height,
|
||||
&context.num_samples);
|
||||
|
||||
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_GUIDING_PREPROCESS, work_size, args);
|
||||
}
|
||||
|
||||
bool OptiXDenoiser::denoise_ensure(DenoiseContext &context)
|
||||
{
|
||||
if (!denoise_create_if_needed(context)) {
|
||||
LOG(ERROR) << "OptiX denoiser creation has failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!denoise_configure_if_needed(context)) {
|
||||
LOG(ERROR) << "OptiX denoiser configuration has failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return DenoiserGPU::denoise_buffer(task);
|
||||
}
|
||||
|
||||
bool OptiXDenoiser::denoise_create_if_needed(DenoiseContext &context)
|
||||
|
||||
@@ -24,29 +24,20 @@ class OptiXDenoiser : public DenoiserGPU {
|
||||
private:
|
||||
virtual bool denoise_buffer(const DenoiseTask &task) override;
|
||||
|
||||
/* Read guiding passes from the render buffers, preprocess them in a way which is expected by
|
||||
* OptiX 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);
|
||||
|
||||
/* Set fake albedo pixels in the albedo guiding pass storage.
|
||||
* After this point only passes which do not need albedo for denoising can be processed. */
|
||||
bool denoise_filter_guiding_set_fake_albedo(const DenoiseContext &context);
|
||||
/* Make sure the OptiX denoiser is created and configured. */
|
||||
bool denoise_ensure(DenoiseContext &context);
|
||||
|
||||
/* Create OptiX denoiser descriptor if needed.
|
||||
* Will do nothing if the current OptiX descriptor is usable for the given parameters.
|
||||
* If the OptiX denoiser descriptor did re-allocate here it is left unconfigured. */
|
||||
bool denoise_create_if_needed(DenoiseContext &context);
|
||||
virtual bool denoise_create_if_needed(DenoiseContext &context) override;
|
||||
|
||||
/* Configure existing OptiX denoiser descriptor for the use for the given task. */
|
||||
bool denoise_configure_if_needed(DenoiseContext &context);
|
||||
virtual bool denoise_configure_if_needed(DenoiseContext &context) override;
|
||||
|
||||
/* Run configured denoiser. */
|
||||
bool denoise_run(const DenoiseContext &context, const DenoisePass &pass) override;
|
||||
virtual bool denoise_run(const DenoiseContext &context, const DenoisePass &pass) override;
|
||||
|
||||
OptixDenoiser optix_denoiser_ = nullptr;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user