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>2020-02-11 18:30:01 +0300
committerPatrick Mours <pmours@nvidia.com>2020-02-11 20:03:43 +0300
commit38589de10c098cfe32ac7716f4d7844abf959753 (patch)
treed28b007bdc75e4eefd1d7ded5115655c50a72140 /intern/cycles/device
parent35490c3ead03d472dbcba36c85d428e81b442520 (diff)
Cycles: Add support for denoising in the viewport
The OptiX denoiser can be a great help when rendering in the viewport, since it is really fast and needs few samples to produce convincing results. This patch therefore adds support for using any Cycles denoiser in the viewport also (but only the OptiX one is selectable because the NLM one is too slow to be usable currently). It also adds support for denoising on a different device than rendering (so one can e.g. render with the CPU but denoise with OptiX). Reviewed By: #cycles, brecht Differential Revision: https://developer.blender.org/D6554
Diffstat (limited to 'intern/cycles/device')
-rw-r--r--intern/cycles/device/device.cpp24
-rw-r--r--intern/cycles/device/device.h1
-rw-r--r--intern/cycles/device/device_cpu.cpp36
-rw-r--r--intern/cycles/device/device_cuda.cpp53
-rw-r--r--intern/cycles/device/device_memory.h5
-rw-r--r--intern/cycles/device/device_multi.cpp136
-rw-r--r--intern/cycles/device/device_optix.cpp64
-rw-r--r--intern/cycles/device/device_task.cpp6
-rw-r--r--intern/cycles/device/device_task.h9
-rw-r--r--intern/cycles/device/opencl/opencl_split.cpp32
10 files changed, 286 insertions, 80 deletions
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index 76670351734..c0d02e0605f 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -366,6 +366,15 @@ void Device::draw_pixels(device_memory &rgba,
Device *Device::create(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background)
{
+#ifdef WITH_MULTI
+ if (!info.multi_devices.empty()) {
+ /* Always create a multi device when info contains multiple devices.
+ * This is done so that the type can still be e.g. DEVICE_CPU to indicate
+ * that it is a homogeneous collection of devices, which simplifies checks. */
+ return device_multi_create(info, stats, profiler, background);
+ }
+#endif
+
Device *device;
switch (info.type) {
@@ -388,11 +397,6 @@ Device *Device::create(DeviceInfo &info, Stats &stats, Profiler &profiler, bool
device = NULL;
break;
#endif
-#ifdef WITH_MULTI
- case DEVICE_MULTI:
- device = device_multi_create(info, stats, profiler, background);
- break;
-#endif
#ifdef WITH_NETWORK
case DEVICE_NETWORK:
device = device_network_create(info, stats, profiler, "127.0.0.1");
@@ -586,7 +590,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
}
DeviceInfo info;
- info.type = DEVICE_MULTI;
+ info.type = subdevices.front().type;
info.id = "MULTI";
info.description = "Multi Device";
info.num = 0;
@@ -624,6 +628,14 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
info.multi_devices.push_back(device);
}
+ /* Create unique ID for this combination of devices. */
+ info.id += device.id;
+
+ /* Set device type to MULTI if subdevices are not of a common type. */
+ if (device.type != info.type) {
+ info.type = DEVICE_MULTI;
+ }
+
/* Accumulate device info. */
info.has_half_images &= device.has_half_images;
info.has_volume_decoupled &= device.has_volume_decoupled;
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index 66fcac921d3..2aeed3f0e89 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -83,6 +83,7 @@ class DeviceInfo {
bool has_profiling; /* Supports runtime collection of profiling info. */
int cpu_threads;
vector<DeviceInfo> multi_devices;
+ vector<DeviceInfo> denoising_devices;
DeviceInfo()
{
diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index c2843a61e6d..42ebf3a8399 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -508,13 +508,14 @@ class CPUDevice : public Device {
void thread_run(DeviceTask *task)
{
- if (task->type == DeviceTask::RENDER) {
+ if (task->type == DeviceTask::RENDER || task->type == DeviceTask::DENOISE)
thread_render(*task);
- }
- else if (task->type == DeviceTask::FILM_CONVERT)
- thread_film_convert(*task);
else if (task->type == DeviceTask::SHADER)
thread_shader(*task);
+ else if (task->type == DeviceTask::FILM_CONVERT)
+ thread_film_convert(*task);
+ else if (task->type == DeviceTask::DENOISE_BUFFER)
+ thread_denoise(*task);
}
class CPUDeviceTask : public DeviceTask {
@@ -954,6 +955,33 @@ class CPUDevice : public Device {
delete split_kernel;
}
+ void thread_denoise(DeviceTask &task)
+ {
+ RenderTile tile;
+ tile.x = task.x;
+ tile.y = task.y;
+ tile.w = task.w;
+ tile.h = task.h;
+ tile.buffer = task.buffer;
+ tile.sample = task.sample + task.num_samples;
+ tile.num_samples = task.num_samples;
+ tile.start_sample = task.sample;
+ tile.offset = task.offset;
+ tile.stride = task.stride;
+ tile.buffers = task.buffers;
+
+ DenoisingTask denoising(this, task);
+
+ ProfilingState denoising_profiler_state;
+ profiler.add_state(&denoising_profiler_state);
+ denoising.profiler = &denoising_profiler_state;
+
+ denoise(denoising, tile);
+ task.update_progress(&tile, tile.w * tile.h);
+
+ profiler.remove_state(&denoising_profiler_state);
+ }
+
void thread_film_convert(DeviceTask &task)
{
float sample_scale = 1.0f / (task.sample + 1);
diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp
index dfd80d678fd..e3c737cc2e7 100644
--- a/intern/cycles/device/device_cuda.cpp
+++ b/intern/cycles/device/device_cuda.cpp
@@ -994,16 +994,16 @@ class CUDADevice : public Device {
else if (mem.type == MEM_TEXTURE) {
assert(!"mem_copy_from not supported for textures.");
}
- else {
- CUDAContextScope scope(this);
- size_t offset = elem * y * w;
- size_t size = elem * w * h;
+ else if (mem.host_pointer) {
+ const size_t size = elem * w * h;
+ const size_t offset = elem * y * w;
- if (mem.host_pointer && mem.device_pointer) {
+ if (mem.device_pointer) {
+ const CUDAContextScope scope(this);
cuda_assert(cuMemcpyDtoH(
- (uchar *)mem.host_pointer + offset, (CUdeviceptr)(mem.device_pointer + offset), size));
+ (char *)mem.host_pointer + offset, (CUdeviceptr)mem.device_pointer + offset, size));
}
- else if (mem.host_pointer) {
+ else {
memset((char *)mem.host_pointer + offset, 0, size);
}
}
@@ -1014,20 +1014,19 @@ class CUDADevice : public Device {
if (!mem.device_pointer) {
mem_alloc(mem);
}
-
- if (mem.host_pointer) {
- memset(mem.host_pointer, 0, mem.memory_size());
+ if (!mem.device_pointer) {
+ return;
}
- /* If use_mapped_host of mem is false, mem.device_pointer currently
- * refers to device memory regardless of mem.host_pointer and
- * mem.shared_pointer. */
-
- if (mem.device_pointer &&
- (cuda_mem_map[&mem].use_mapped_host == false || mem.host_pointer != mem.shared_pointer)) {
- CUDAContextScope scope(this);
+ /* If use_mapped_host of mem is false, mem.device_pointer currently refers to device memory
+ * regardless of mem.host_pointer and mem.shared_pointer. */
+ if (!cuda_mem_map[&mem].use_mapped_host || mem.host_pointer != mem.shared_pointer) {
+ const CUDAContextScope scope(this);
cuda_assert(cuMemsetD8(cuda_device_ptr(mem.device_pointer), 0, mem.memory_size()));
}
+ else if (mem.host_pointer) {
+ memset(mem.host_pointer, 0, mem.memory_size());
+ }
}
void mem_free(device_memory &mem)
@@ -2240,7 +2239,7 @@ class CUDADevice : public Device {
{
CUDAContextScope scope(this);
- if (task->type == DeviceTask::RENDER) {
+ if (task->type == DeviceTask::RENDER || task->type == DeviceTask::DENOISE) {
DeviceRequestedFeatures requested_features;
if (use_split_kernel()) {
if (split_kernel == NULL) {
@@ -2288,6 +2287,24 @@ class CUDADevice : public Device {
cuda_assert(cuCtxSynchronize());
}
+ else if (task->type == DeviceTask::DENOISE_BUFFER) {
+ RenderTile tile;
+ tile.x = task->x;
+ tile.y = task->y;
+ tile.w = task->w;
+ tile.h = task->h;
+ tile.buffer = task->buffer;
+ tile.sample = task->sample + task->num_samples;
+ tile.num_samples = task->num_samples;
+ tile.start_sample = task->sample;
+ tile.offset = task->offset;
+ tile.stride = task->stride;
+ tile.buffers = task->buffers;
+
+ DenoisingTask denoising(this, *task);
+ denoise(tile, denoising);
+ task->update_progress(&tile, tile.w * tile.h);
+ }
}
class CUDADeviceTask : public DeviceTask {
diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h
index 60740807568..2949773ef0c 100644
--- a/intern/cycles/device/device_memory.h
+++ b/intern/cycles/device/device_memory.h
@@ -427,6 +427,11 @@ template<typename T> class device_vector : public device_memory {
device_copy_to();
}
+ void copy_from_device()
+ {
+ device_copy_from(0, data_width, data_height, sizeof(T));
+ }
+
void copy_from_device(int y, int w, int h)
{
device_copy_from(y, w, h, sizeof(T));
diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp
index b8587eb0a62..9cbf69a191a 100644
--- a/intern/cycles/device/device_multi.cpp
+++ b/intern/cycles/device/device_multi.cpp
@@ -42,7 +42,7 @@ class MultiDevice : public Device {
map<device_ptr, device_ptr> ptr_map;
};
- list<SubDevice> devices;
+ list<SubDevice> devices, denoising_devices;
device_ptr unique_key;
MultiDevice(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background_)
@@ -61,6 +61,12 @@ class MultiDevice : public Device {
}
}
+ foreach (DeviceInfo &subinfo, info.denoising_devices) {
+ Device *device = Device::create(subinfo, sub_stats_, profiler, background);
+
+ denoising_devices.push_back(SubDevice(device));
+ }
+
#ifdef WITH_NETWORK
/* try to add network devices */
ServerDiscovery discovery(true);
@@ -80,17 +86,18 @@ class MultiDevice : public Device {
{
foreach (SubDevice &sub, devices)
delete sub.device;
+ foreach (SubDevice &sub, denoising_devices)
+ delete sub.device;
}
const string &error_message()
{
- foreach (SubDevice &sub, devices) {
- if (sub.device->error_message() != "") {
- if (error_msg == "")
- error_msg = sub.device->error_message();
- break;
- }
- }
+ error_msg.clear();
+
+ foreach (SubDevice &sub, devices)
+ error_msg += sub.device->error_message();
+ foreach (SubDevice &sub, denoising_devices)
+ error_msg += sub.device->error_message();
return error_msg;
}
@@ -118,6 +125,12 @@ class MultiDevice : public Device {
if (!sub.device->load_kernels(requested_features))
return false;
+ if (requested_features.use_denoising) {
+ foreach (SubDevice &sub, denoising_devices)
+ if (!sub.device->load_kernels(requested_features))
+ return false;
+ }
+
return true;
}
@@ -127,6 +140,12 @@ class MultiDevice : public Device {
if (!sub.device->wait_for_availability(requested_features))
return false;
+ if (requested_features.use_denoising) {
+ foreach (SubDevice &sub, denoising_devices)
+ if (!sub.device->wait_for_availability(requested_features))
+ return false;
+ }
+
return true;
}
@@ -150,16 +169,17 @@ class MultiDevice : public Device {
break;
}
}
+
return result;
}
bool build_optix_bvh(BVH *bvh)
{
- // Broadcast acceleration structure build to all devices
- foreach (SubDevice &sub, devices) {
+ // Broadcast acceleration structure build to all render devices
+ foreach (SubDevice &sub, devices)
if (!sub.device->build_optix_bvh(bvh))
return false;
- }
+
return true;
}
@@ -236,6 +256,17 @@ class MultiDevice : public Device {
sub.ptr_map[key] = mem.device_pointer;
}
+ if (strcmp(mem.name, "RenderBuffers") == 0) {
+ foreach (SubDevice &sub, denoising_devices) {
+ mem.device = sub.device;
+ mem.device_pointer = (existing_key) ? sub.ptr_map[existing_key] : 0;
+ mem.device_size = existing_size;
+
+ sub.device->mem_zero(mem);
+ sub.ptr_map[key] = mem.device_pointer;
+ }
+ }
+
mem.device = this;
mem.device_pointer = key;
stats.mem_alloc(mem.device_size - existing_size);
@@ -255,6 +286,17 @@ class MultiDevice : public Device {
sub.ptr_map.erase(sub.ptr_map.find(key));
}
+ if (strcmp(mem.name, "RenderBuffers") == 0) {
+ foreach (SubDevice &sub, denoising_devices) {
+ mem.device = sub.device;
+ mem.device_pointer = sub.ptr_map[key];
+ mem.device_size = existing_size;
+
+ sub.device->mem_free(mem);
+ sub.ptr_map.erase(sub.ptr_map.find(key));
+ }
+ }
+
mem.device = this;
mem.device_pointer = 0;
mem.device_size = 0;
@@ -302,10 +344,21 @@ class MultiDevice : public Device {
void map_tile(Device *sub_device, RenderTile &tile)
{
+ if (!tile.buffer) {
+ return;
+ }
+
foreach (SubDevice &sub, devices) {
if (sub.device == sub_device) {
- if (tile.buffer)
- tile.buffer = sub.ptr_map[tile.buffer];
+ tile.buffer = sub.ptr_map[tile.buffer];
+ return;
+ }
+ }
+
+ foreach (SubDevice &sub, denoising_devices) {
+ if (sub.device == sub_device) {
+ tile.buffer = sub.ptr_map[tile.buffer];
+ return;
}
}
}
@@ -320,6 +373,12 @@ class MultiDevice : public Device {
i++;
}
+ foreach (SubDevice &sub, denoising_devices) {
+ if (sub.device == sub_device)
+ return i;
+ i++;
+ }
+
return -1;
}
@@ -330,11 +389,20 @@ class MultiDevice : public Device {
continue;
}
+ device_vector<float> &mem = tiles[i].buffers->buffer;
+ tiles[i].buffer = mem.device_pointer;
+
+ if (mem.device == this && denoising_devices.empty()) {
+ /* Skip unnecessary copies in viewport mode (buffer covers the
+ * whole image), but still need to fix up the tile evice pointer. */
+ map_tile(sub_device, tiles[i]);
+ continue;
+ }
+
/* If the tile was rendered on another device, copy its memory to
* to the current device now, for the duration of the denoising task.
* Note that this temporarily modifies the RenderBuffers and calls
* the device, so this function is not thread safe. */
- device_vector<float> &mem = tiles[i].buffers->buffer;
if (mem.device != sub_device) {
/* Only copy from device to host once. This is faster, but
* also required for the case where a CPU thread is denoising
@@ -342,12 +410,20 @@ class MultiDevice : public Device {
* overwriting the buffer being denoised by the CPU thread. */
if (!tiles[i].buffers->map_neighbor_copied) {
tiles[i].buffers->map_neighbor_copied = true;
- mem.copy_from_device(0, mem.data_size, 1);
+ mem.copy_from_device();
}
- mem.swap_device(sub_device, 0, 0);
+ if (mem.device == this) {
+ /* Can re-use memory if tile is already allocated on the sub device. */
+ map_tile(sub_device, tiles[i]);
+ mem.swap_device(sub_device, mem.device_size, tiles[i].buffer);
+ }
+ else {
+ mem.swap_device(sub_device, 0, 0);
+ }
mem.copy_to_device();
+
tiles[i].buffer = mem.device_pointer;
tiles[i].device_size = mem.device_size;
@@ -358,11 +434,17 @@ class MultiDevice : public Device {
void unmap_neighbor_tiles(Device *sub_device, RenderTile *tiles)
{
- /* Copy denoised result back to the host. */
device_vector<float> &mem = tiles[9].buffers->buffer;
+
+ if (mem.device == this && denoising_devices.empty()) {
+ return;
+ }
+
+ /* Copy denoised result back to the host. */
mem.swap_device(sub_device, tiles[9].device_size, tiles[9].buffer);
- mem.copy_from_device(0, mem.data_size, 1);
+ mem.copy_from_device();
mem.restore_device();
+
/* Copy denoised result to the original device. */
mem.copy_to_device();
@@ -372,7 +454,9 @@ class MultiDevice : public Device {
}
device_vector<float> &mem = tiles[i].buffers->buffer;
- if (mem.device != sub_device) {
+
+ if (mem.device != sub_device && mem.device != this) {
+ /* Free up memory again if it was allocated for the copy above. */
mem.swap_device(sub_device, tiles[i].device_size, tiles[i].buffer);
sub_device->mem_free(mem);
mem.restore_device();
@@ -398,10 +482,16 @@ class MultiDevice : public Device {
void task_add(DeviceTask &task)
{
+ list<SubDevice> &task_devices = denoising_devices.empty() ||
+ (task.type != DeviceTask::DENOISE &&
+ task.type != DeviceTask::DENOISE_BUFFER) ?
+ devices :
+ denoising_devices;
+
list<DeviceTask> tasks;
- task.split(tasks, devices.size());
+ task.split(tasks, task_devices.size());
- foreach (SubDevice &sub, devices) {
+ foreach (SubDevice &sub, task_devices) {
if (!tasks.empty()) {
DeviceTask subtask = tasks.front();
tasks.pop_front();
@@ -426,12 +516,16 @@ class MultiDevice : public Device {
{
foreach (SubDevice &sub, devices)
sub.device->task_wait();
+ foreach (SubDevice &sub, denoising_devices)
+ sub.device->task_wait();
}
void task_cancel()
{
foreach (SubDevice &sub, devices)
sub.device->task_cancel();
+ foreach (SubDevice &sub, denoising_devices)
+ sub.device->task_cancel();
}
protected:
diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp
index 98469fb37b0..ac119a723e3 100644
--- a/intern/cycles/device/device_optix.cpp
+++ b/intern/cycles/device/device_optix.cpp
@@ -213,6 +213,7 @@ class OptiXDevice : public Device {
OptixDenoiser denoiser = NULL;
vector<pair<int2, CUdeviceptr>> denoiser_state;
+ int denoiser_input_passes = 0;
public:
OptiXDevice(DeviceInfo &info_, Stats &stats_, Profiler &profiler_, bool background_)
@@ -632,7 +633,7 @@ class OptiXDevice : public Device {
if (have_error())
return; // Abort early if there was an error previously
- if (task.type == DeviceTask::RENDER) {
+ if (task.type == DeviceTask::RENDER || task.type == DeviceTask::DENOISE) {
RenderTile tile;
while (task.acquire_tile(this, tile)) {
if (tile.task == RenderTile::PATH_TRACE)
@@ -652,6 +653,22 @@ class OptiXDevice : public Device {
else if (task.type == DeviceTask::FILM_CONVERT) {
launch_film_convert(task, thread_index);
}
+ else if (task.type == DeviceTask::DENOISE_BUFFER) {
+ // Set up a single tile that covers the whole task and denoise it
+ RenderTile tile;
+ tile.x = task.x;
+ tile.y = task.y;
+ tile.w = task.w;
+ tile.h = task.h;
+ tile.buffer = task.buffer;
+ tile.num_samples = task.num_samples;
+ tile.start_sample = task.sample;
+ tile.offset = task.offset;
+ tile.stride = task.stride;
+ tile.buffers = task.buffers;
+
+ launch_denoise(task, tile, thread_index);
+ }
}
void launch_render(DeviceTask &task, RenderTile &rtile, int thread_index)
@@ -740,6 +757,7 @@ class OptiXDevice : public Device {
RenderTile rtiles[10];
rtiles[4] = rtile;
task.map_neighbor_tiles(rtiles, this);
+ rtile = rtiles[4]; // Tile may have been modified by mapping code
// Calculate size of the tile to denoise (including overlap)
int4 rect = make_int4(
@@ -846,7 +864,14 @@ class OptiXDevice : public Device {
}
# endif
- if (denoiser == NULL) {
+ const bool recreate_denoiser = (denoiser == NULL) ||
+ (task.denoising.optix_input_passes != denoiser_input_passes);
+ if (recreate_denoiser) {
+ // Destroy existing handle before creating new one
+ if (denoiser != NULL) {
+ optixDenoiserDestroy(denoiser);
+ }
+
// Create OptiX denoiser handle on demand when it is first used
OptixDenoiserOptions denoiser_options;
assert(task.denoising.optix_input_passes >= 1 && task.denoising.optix_input_passes <= 3);
@@ -856,6 +881,9 @@ class OptiXDevice : public Device {
check_result_optix_ret(optixDenoiserCreate(context, &denoiser_options, &denoiser));
check_result_optix_ret(
optixDenoiserSetModel(denoiser, OPTIX_DENOISER_MODEL_KIND_HDR, NULL, 0));
+
+ // OptiX denoiser handle was created with the requested number of input passes
+ denoiser_input_passes = task.denoising.optix_input_passes;
}
OptixDenoiserSizes sizes = {};
@@ -868,13 +896,16 @@ class OptiXDevice : public Device {
const size_t scratch_offset = sizes.stateSizeInBytes;
// Allocate denoiser state if tile size has changed since last setup
- if (state_size.x != rect_size.x || state_size.y != rect_size.y) {
+ if (state_size.x != rect_size.x || state_size.y != rect_size.y || recreate_denoiser) {
+ // Free existing state before allocating new one
if (state) {
cuMemFree(state);
state = 0;
}
+
check_result_cuda_ret(cuMemAlloc(&state, scratch_offset + scratch_size));
+ // Initialize denoiser state for the current tile size
check_result_optix_ret(optixDenoiserSetup(denoiser,
cuda_stream[thread_index],
rect_size.x,
@@ -1972,17 +2003,17 @@ class OptiXDevice : public Device {
else if (mem.type == MEM_TEXTURE) {
assert(!"mem_copy_from not supported for textures.");
}
- else {
+ else if (mem.host_pointer) {
// Calculate linear memory offset and size
const size_t size = elem * w * h;
const size_t offset = elem * y * w;
- if (mem.host_pointer && mem.device_pointer) {
+ if (mem.device_pointer) {
const CUDAContextScope scope(cuda_context);
check_result_cuda(cuMemcpyDtoH(
(char *)mem.host_pointer + offset, (CUdeviceptr)mem.device_pointer + offset, size));
}
- else if (mem.host_pointer) {
+ else {
memset((char *)mem.host_pointer + offset, 0, size);
}
}
@@ -1990,21 +2021,22 @@ class OptiXDevice : public Device {
void mem_zero(device_memory &mem) override
{
- if (mem.host_pointer)
- memset(mem.host_pointer, 0, mem.memory_size());
-
- if (!mem.device_pointer)
+ if (!mem.device_pointer) {
mem_alloc(mem); // Need to allocate memory first if it does not exist yet
+ }
+ if (!mem.device_pointer) {
+ return;
+ }
- /* If use_mapped_host of mem is false, mem.device_pointer currently
- * refers to device memory regardless of mem.host_pointer and
- * mem.shared_pointer. */
-
- if (mem.device_pointer &&
- (cuda_mem_map[&mem].use_mapped_host == false || mem.host_pointer != mem.shared_pointer)) {
+ /* If use_mapped_host of mem is false, mem.device_pointer currently refers to device memory
+ * regardless of mem.host_pointer and mem.shared_pointer. */
+ if (!cuda_mem_map[&mem].use_mapped_host || mem.host_pointer != mem.shared_pointer) {
const CUDAContextScope scope(cuda_context);
check_result_cuda(cuMemsetD8((CUdeviceptr)mem.device_pointer, 0, mem.memory_size()));
}
+ else if (mem.host_pointer) {
+ memset(mem.host_pointer, 0, mem.memory_size());
+ }
}
void mem_free(device_memory &mem) override
diff --git a/intern/cycles/device/device_task.cpp b/intern/cycles/device/device_task.cpp
index 376ad06a734..8f15e8c8c1e 100644
--- a/intern/cycles/device/device_task.cpp
+++ b/intern/cycles/device/device_task.cpp
@@ -68,7 +68,7 @@ int DeviceTask::get_subtask_count(int num, int max_size)
if (type == SHADER) {
num = min(shader_w, num);
}
- else if (type == RENDER) {
+ else if (type == RENDER || type == DENOISE) {
}
else {
num = min(h, num);
@@ -94,7 +94,7 @@ void DeviceTask::split(list<DeviceTask> &tasks, int num, int max_size)
tasks.push_back(task);
}
}
- else if (type == RENDER) {
+ else if (type == RENDER || type == DENOISE) {
for (int i = 0; i < num; i++)
tasks.push_back(*this);
}
@@ -115,7 +115,7 @@ void DeviceTask::split(list<DeviceTask> &tasks, int num, int max_size)
void DeviceTask::update_progress(RenderTile *rtile, int pixel_samples)
{
- if ((type != RENDER) && (type != SHADER))
+ if (type == FILM_CONVERT)
return;
if (update_progress_sample) {
diff --git a/intern/cycles/device/device_task.h b/intern/cycles/device/device_task.h
index 1b1e97cdb10..0f718528b86 100644
--- a/intern/cycles/device/device_task.h
+++ b/intern/cycles/device/device_task.h
@@ -47,7 +47,7 @@ class DenoiseParams {
int neighbor_frames;
/* Clamp the input to the range of +-1e8. Should be enough for any legitimate data. */
bool clamp_input;
- /* Controls which passes the OptiX AI denoiser should use as input. */
+ /* Passes handed over to the OptiX denoiser (default to color + albedo). */
int optix_input_passes;
DenoiseParams()
@@ -58,13 +58,13 @@ class DenoiseParams {
relative_pca = false;
neighbor_frames = 2;
clamp_input = true;
- optix_input_passes = 1;
+ optix_input_passes = 2;
}
};
class DeviceTask : public Task {
public:
- typedef enum { RENDER, FILM_CONVERT, SHADER } Type;
+ typedef enum { RENDER, DENOISE, DENOISE_BUFFER, FILM_CONVERT, SHADER } Type;
Type type;
int x, y, w, h;
@@ -81,7 +81,7 @@ class DeviceTask : public Task {
int shader_filter;
int shader_x, shader_w;
- int passes_size;
+ RenderBuffers *buffers;
explicit DeviceTask(Type type = RENDER);
@@ -114,7 +114,6 @@ class DeviceTask : public Task {
bool need_finish_queue;
bool integrator_branched;
- int2 requested_tile_size;
protected:
double last_update_time;
diff --git a/intern/cycles/device/opencl/opencl_split.cpp b/intern/cycles/device/opencl/opencl_split.cpp
index 76f9ce7a18f..af40aa89db4 100644
--- a/intern/cycles/device/opencl/opencl_split.cpp
+++ b/intern/cycles/device/opencl/opencl_split.cpp
@@ -1308,13 +1308,7 @@ void OpenCLDevice::thread_run(DeviceTask *task)
{
flush_texture_buffers();
- if (task->type == DeviceTask::FILM_CONVERT) {
- film_convert(*task, task->buffer, task->rgba_byte, task->rgba_half);
- }
- else if (task->type == DeviceTask::SHADER) {
- shader(*task);
- }
- else if (task->type == DeviceTask::RENDER) {
+ if (task->type == DeviceTask::RENDER || task->type == DeviceTask::DENOISE) {
RenderTile tile;
DenoisingTask denoising(this, *task);
@@ -1352,6 +1346,30 @@ void OpenCLDevice::thread_run(DeviceTask *task)
kgbuffer.free();
}
+ else if (task->type == DeviceTask::SHADER) {
+ shader(*task);
+ }
+ else if (task->type == DeviceTask::FILM_CONVERT) {
+ film_convert(*task, task->buffer, task->rgba_byte, task->rgba_half);
+ }
+ else if (task->type == DeviceTask::DENOISE_BUFFER) {
+ RenderTile tile;
+ tile.x = task->x;
+ tile.y = task->y;
+ tile.w = task->w;
+ tile.h = task->h;
+ tile.buffer = task->buffer;
+ tile.sample = task->sample + task->num_samples;
+ tile.num_samples = task->num_samples;
+ tile.start_sample = task->sample;
+ tile.offset = task->offset;
+ tile.stride = task->stride;
+ tile.buffers = task->buffers;
+
+ DenoisingTask denoising(this, *task);
+ denoise(tile, denoising);
+ task->update_progress(&tile, tile.w * tile.h);
+ }
}
void OpenCLDevice::film_convert(DeviceTask &task,