* Split render/ into scene/ and session/. The scene/ folder now contains the scene and its nodes. The session/ folder contains the render session and associated data structures like drivers and render buffers. * Move top level kernel headers into new folders kernel/camera/, kernel/film/, kernel/light/, kernel/sample/, kernel/util/ * Move integrator related kernel headers into kernel/integrator/ * Move OSL shaders from kernel/shaders/ to kernel/osl/shaders/ For patches and branches, git merge and rebase should be able to detect the renames and move over code to the right file.
205 lines
5.8 KiB
C++
205 lines
5.8 KiB
C++
/*
|
|
* Copyright 2011-2021 Blender Foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "integrator/denoiser.h"
|
|
|
|
#include "device/device.h"
|
|
#include "integrator/denoiser_oidn.h"
|
|
#include "integrator/denoiser_optix.h"
|
|
#include "session/buffers.h"
|
|
#include "util/util_logging.h"
|
|
#include "util/util_progress.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
unique_ptr<Denoiser> Denoiser::create(Device *path_trace_device, const DenoiseParams ¶ms)
|
|
{
|
|
DCHECK(params.use);
|
|
|
|
switch (params.type) {
|
|
case DENOISER_OPTIX:
|
|
return make_unique<OptiXDenoiser>(path_trace_device, params);
|
|
|
|
case DENOISER_OPENIMAGEDENOISE:
|
|
return make_unique<OIDNDenoiser>(path_trace_device, params);
|
|
|
|
case DENOISER_NUM:
|
|
case DENOISER_NONE:
|
|
case DENOISER_ALL:
|
|
/* pass */
|
|
break;
|
|
}
|
|
|
|
LOG(FATAL) << "Unhandled denoiser type " << params.type << ", should never happen.";
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
Denoiser::Denoiser(Device *path_trace_device, const DenoiseParams ¶ms)
|
|
: path_trace_device_(path_trace_device), params_(params)
|
|
{
|
|
DCHECK(params.use);
|
|
}
|
|
|
|
void Denoiser::set_params(const DenoiseParams ¶ms)
|
|
{
|
|
DCHECK_EQ(params.type, params_.type);
|
|
|
|
if (params.type == params_.type) {
|
|
params_ = params;
|
|
}
|
|
else {
|
|
LOG(ERROR) << "Attempt to change denoiser type.";
|
|
}
|
|
}
|
|
|
|
const DenoiseParams &Denoiser::get_params() const
|
|
{
|
|
return params_;
|
|
}
|
|
|
|
bool Denoiser::load_kernels(Progress *progress)
|
|
{
|
|
const Device *denoiser_device = ensure_denoiser_device(progress);
|
|
|
|
if (!denoiser_device) {
|
|
path_trace_device_->set_error("No device available to denoise on");
|
|
return false;
|
|
}
|
|
|
|
VLOG(3) << "Will denoise on " << denoiser_device->info.description << " ("
|
|
<< denoiser_device->info.id << ")";
|
|
|
|
return true;
|
|
}
|
|
|
|
Device *Denoiser::get_denoiser_device() const
|
|
{
|
|
return denoiser_device_;
|
|
}
|
|
|
|
/* Check whether given device is single (not a MultiDevice) and supports requested denoiser. */
|
|
static bool is_single_supported_device(Device *device, DenoiserType type)
|
|
{
|
|
if (device->info.type == DEVICE_MULTI) {
|
|
/* Assume multi-device is never created with a single sub-device.
|
|
* If one requests such configuration it should be checked on the session level. */
|
|
return false;
|
|
}
|
|
|
|
if (!device->info.multi_devices.empty()) {
|
|
/* Some configurations will use multi_devices, but keep the type of an individual device.
|
|
* This does simplify checks for homogenous setups, but here we really need a single device. */
|
|
return false;
|
|
}
|
|
|
|
/* Check the denoiser type is supported. */
|
|
return (device->info.denoisers & type);
|
|
}
|
|
|
|
/* Find best suitable device to perform denoiser on. Will iterate over possible sub-devices of
|
|
* multi-device.
|
|
*
|
|
* If there is no device available which supports given denoiser type nullptr is returned. */
|
|
static Device *find_best_device(Device *device, DenoiserType type)
|
|
{
|
|
Device *best_device = nullptr;
|
|
|
|
device->foreach_device([&](Device *sub_device) {
|
|
if ((sub_device->info.denoisers & type) == 0) {
|
|
return;
|
|
}
|
|
if (!best_device) {
|
|
best_device = sub_device;
|
|
}
|
|
else {
|
|
/* TODO(sergey): Choose fastest device from available ones. Taking into account performance
|
|
* of the device and data transfer cost. */
|
|
}
|
|
});
|
|
|
|
return best_device;
|
|
}
|
|
|
|
static unique_ptr<Device> create_denoiser_device(Device *path_trace_device,
|
|
const uint device_type_mask)
|
|
{
|
|
const vector<DeviceInfo> device_infos = Device::available_devices(device_type_mask);
|
|
if (device_infos.empty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
/* TODO(sergey): Use one of the already configured devices, so that OptiX denoising can happen on
|
|
* a physical CUDA device which is already used for rendering. */
|
|
|
|
/* TODO(sergey): Choose fastest device for denoising. */
|
|
|
|
const DeviceInfo denoiser_device_info = device_infos.front();
|
|
|
|
unique_ptr<Device> denoiser_device(
|
|
Device::create(denoiser_device_info, path_trace_device->stats, path_trace_device->profiler));
|
|
|
|
if (!denoiser_device) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (denoiser_device->have_error()) {
|
|
return nullptr;
|
|
}
|
|
|
|
/* Only need denoising feature, everything else is unused. */
|
|
if (!denoiser_device->load_kernels(KERNEL_FEATURE_DENOISING)) {
|
|
return nullptr;
|
|
}
|
|
|
|
return denoiser_device;
|
|
}
|
|
|
|
Device *Denoiser::ensure_denoiser_device(Progress *progress)
|
|
{
|
|
/* The best device has been found already, avoid sequential lookups.
|
|
* Additionally, avoid device re-creation if it has failed once. */
|
|
if (denoiser_device_ || device_creation_attempted_) {
|
|
return denoiser_device_;
|
|
}
|
|
|
|
/* Simple case: rendering happens on a single device which also supports denoiser. */
|
|
if (is_single_supported_device(path_trace_device_, params_.type)) {
|
|
denoiser_device_ = path_trace_device_;
|
|
return denoiser_device_;
|
|
}
|
|
|
|
/* Find best device from the ones which are already used for rendering. */
|
|
denoiser_device_ = find_best_device(path_trace_device_, params_.type);
|
|
if (denoiser_device_) {
|
|
return denoiser_device_;
|
|
}
|
|
|
|
if (progress) {
|
|
progress->set_status("Loading denoising kernels (may take a few minutes the first time)");
|
|
}
|
|
|
|
device_creation_attempted_ = true;
|
|
|
|
const uint device_type_mask = get_device_type_mask();
|
|
local_denoiser_device_ = create_denoiser_device(path_trace_device_, device_type_mask);
|
|
denoiser_device_ = local_denoiser_device_.get();
|
|
|
|
return denoiser_device_;
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|