Commit: 94efc651d40fe62417b605e2f400fd364fb0d8ef Author: Lukas Stockner Date: Sat Aug 25 12:19:44 2018 -0700 Branches: master https://developer.blender.org/rB94efc651d40fe62417b605e2f400fd364fb0d8ef
Cycles Denoiser: Allocate a single temporary buffer for the entire denoising process With small tiles, the repeated allocations on GPUs can actually slow down the denoising quite a lot. Allocating the buffer just once reduces rendertime for the default cube with 16x16 tiles and denoising on a mobile 1050 from 22.7sec to 14.0sec. =================================================================== M intern/cycles/device/device_cpu.cpp M intern/cycles/device/device_cuda.cpp M intern/cycles/device/device_denoising.cpp M intern/cycles/device/device_denoising.h M intern/cycles/device/opencl/opencl_base.cpp =================================================================== diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index 6867dffc727..e92bbbfa6e6 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -471,9 +471,10 @@ public: int w = align_up(rect.z-rect.x, 4); int h = rect.w-rect.y; - float *blurDifference = (float*) task->nlm_state.temporary_1_ptr; - float *difference = (float*) task->nlm_state.temporary_2_ptr; - float *weightAccum = (float*) task->nlm_state.temporary_3_ptr; + float *temporary_mem = (float*) task->buffer.temporary_mem.device_pointer; + float *blurDifference = temporary_mem; + float *difference = temporary_mem + task->buffer.pass_stride; + float *weightAccum = temporary_mem + 2*task->buffer.pass_stride; memset(weightAccum, 0, sizeof(float)*w*h); memset((float*) out_ptr, 0, sizeof(float)*w*h); @@ -537,8 +538,9 @@ public: mem_zero(task->storage.XtWX); mem_zero(task->storage.XtWY); - float *difference = (float*) task->reconstruction_state.temporary_1_ptr; - float *blurDifference = (float*) task->reconstruction_state.temporary_2_ptr; + float *temporary_mem = (float*) task->buffer.temporary_mem.device_pointer; + float *difference = temporary_mem; + float *blurDifference = temporary_mem + task->buffer.pass_stride; int r = task->radius; for(int i = 0; i < (2*r+1)*(2*r+1); i++) { @@ -713,6 +715,7 @@ public: denoising.filter_area = make_int4(tile.x, tile.y, tile.w, tile.h); denoising.render_buffer.samples = tile.sample; + denoising.buffer.gpu_temporary_mem = false; denoising.run_denoising(&tile); } diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 73c9697223d..da8e49f129f 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -1294,23 +1294,19 @@ public: float a = task->nlm_state.a; float k_2 = task->nlm_state.k_2; - int shift_stride = stride*h; + int pass_stride = task->buffer.pass_stride; int num_shifts = (2*r+1)*(2*r+1); - int mem_size = sizeof(float)*shift_stride*num_shifts; int channel_offset = 0; - device_only_memory<uchar> temporary_mem(this, "Denoising temporary_mem"); - temporary_mem.alloc_to_device(2*mem_size); - if(have_error()) return false; - CUdeviceptr difference = cuda_device_ptr(temporary_mem.device_pointer); - CUdeviceptr blurDifference = difference + mem_size; + CUdeviceptr difference = cuda_device_ptr(task->buffer.temporary_mem.device_pointer); + CUdeviceptr blurDifference = difference + sizeof(float)*pass_stride*num_shifts; + CUdeviceptr weightAccum = difference + 2*sizeof(float)*pass_stride*num_shifts; - CUdeviceptr weightAccum = task->nlm_state.temporary_3_ptr; - cuda_assert(cuMemsetD8(weightAccum, 0, sizeof(float)*shift_stride)); - cuda_assert(cuMemsetD8(out_ptr, 0, sizeof(float)*shift_stride)); + cuda_assert(cuMemsetD8(weightAccum, 0, sizeof(float)*pass_stride)); + cuda_assert(cuMemsetD8(out_ptr, 0, sizeof(float)*pass_stride)); { CUfunction cuNLMCalcDifference, cuNLMBlur, cuNLMCalcWeight, cuNLMUpdateOutput; @@ -1326,10 +1322,10 @@ public: CUDA_GET_BLOCKSIZE_1D(cuNLMCalcDifference, w*h, num_shifts); - void *calc_difference_args[] = {&guide_ptr, &variance_ptr, &difference, &w, &h, &stride, &shift_stride, &r, &channel_offset, &a, &k_2}; - void *blur_args[] = {&difference, &blurDifference, &w, &h, &stride, &shift_stride, &r, &f}; - void *calc_weight_args[] = {&blurDifference, &difference, &w, &h, &stride, &shift_stride, &r, &f}; - void *update_output_args[] = {&blurDifference, &image_ptr, &out_ptr, &weightAccum, &w, &h, &stride, &shift_stride, &r, &f}; + void *calc_difference_args[] = {&guide_ptr, &variance_ptr, &difference, &w, &h, &stride, &pass_stride, &r, &channel_offset, &a, &k_2}; + void *blur_args[] = {&difference, &blurDifference, &w, &h, &stride, &pass_stride, &r, &f}; + void *calc_weight_args[] = {&blurDifference, &difference, &w, &h, &stride, &pass_stride, &r, &f}; + void *update_output_args[] = {&blurDifference, &image_ptr, &out_ptr, &weightAccum, &w, &h, &stride, &pass_stride, &r, &f}; CUDA_LAUNCH_KERNEL_1D(cuNLMCalcDifference, calc_difference_args); CUDA_LAUNCH_KERNEL_1D(cuNLMBlur, blur_args); @@ -1338,8 +1334,6 @@ public: CUDA_LAUNCH_KERNEL_1D(cuNLMUpdateOutput, update_output_args); } - temporary_mem.free(); - { CUfunction cuNLMNormalize; cuda_assert(cuModuleGetFunction(&cuNLMNormalize, cuFilterModule, "kernel_cuda_filter_nlm_normalize")); @@ -1614,6 +1608,7 @@ public: denoising.filter_area = make_int4(rtile.x, rtile.y, rtile.w, rtile.h); denoising.render_buffer.samples = rtile.sample; + denoising.buffer.gpu_temporary_mem = true; denoising.run_denoising(&rtile); } diff --git a/intern/cycles/device/device_denoising.cpp b/intern/cycles/device/device_denoising.cpp index c0d4634262d..23c18fa15b2 100644 --- a/intern/cycles/device/device_denoising.cpp +++ b/intern/cycles/device/device_denoising.cpp @@ -51,10 +51,8 @@ DenoisingTask::~DenoisingTask() storage.XtWY.free(); storage.transform.free(); storage.rank.free(); - storage.temporary_1.free(); - storage.temporary_2.free(); - storage.temporary_color.free(); buffer.mem.free(); + buffer.temporary_mem.free(); tile_info_mem.free(); } @@ -99,6 +97,16 @@ void DenoisingTask::setup_denoising_buffer() /* Pad the total size by four floats since the SIMD kernels might go a bit over the end. */ int mem_size = align_up(buffer.pass_stride * buffer.passes + 4, alignment_floats); buffer.mem.alloc_to_device(mem_size, false); + + /* CPUs process shifts sequentially while GPUs process them in parallel. */ + int num_shifts = 1; + if(buffer.gpu_temporary_mem) { + /* Shadowing prefiltering uses a radius of 6, so allocate at least that much. */ + int max_radius = max(radius, 6); + num_shifts = (2*max_radius + 1) * (2*max_radius + 1); + } + /* Allocate two layers per shift as well as one for the weight accumulation. */ + buffer.temporary_mem.alloc_to_device((2*num_shifts + 1) * buffer.pass_stride); } void DenoisingTask::prefilter_shadowing() @@ -111,13 +119,6 @@ void DenoisingTask::prefilter_shadowing() device_sub_ptr sample_var_var (buffer.mem, 3*buffer.pass_stride, buffer.pass_stride); device_sub_ptr buffer_var (buffer.mem, 5*buffer.pass_stride, buffer.pass_stride); device_sub_ptr filtered_var (buffer.mem, 6*buffer.pass_stride, buffer.pass_stride); - device_sub_ptr nlm_temporary_1(buffer.mem, 7*buffer.pass_stride, buffer.pass_stride); - device_sub_ptr nlm_temporary_2(buffer.mem, 8*buffer.pass_stride, buffer.pass_stride); - device_sub_ptr nlm_temporary_3(buffer.mem, 9*buffer.pass_stride, buffer.pass_stride); - - nlm_state.temporary_1_ptr = *nlm_temporary_1; - nlm_state.temporary_2_ptr = *nlm_temporary_2; - nlm_state.temporary_3_ptr = *nlm_temporary_3; /* Get the A/B unfiltered passes, the combined sample variance, the estimated variance of the sample variance and the buffer variance. */ functions.divide_shadow(*unfiltered_a, *unfiltered_b, *sample_var, *sample_var_var, *buffer_var); @@ -154,13 +155,6 @@ void DenoisingTask::prefilter_features() { device_sub_ptr unfiltered (buffer.mem, 8*buffer.pass_stride, buffer.pass_stride); device_sub_ptr variance (buffer.mem, 9*buffer.pass_stride, buffer.pass_stride); - device_sub_ptr nlm_temporary_1(buffer.mem, 10*buffer.pass_stride, buffer.pass_stride); - device_sub_ptr nlm_temporary_2(buffer.mem, 11*buffer.pass_stride, buffer.pass_stride); - device_sub_ptr nlm_temporary_3(buffer.mem, 12*buffer.pass_stride, buffer.pass_stride); - - nlm_state.temporary_1_ptr = *nlm_temporary_1; - nlm_state.temporary_2_ptr = *nlm_temporary_2; - nlm_state.temporary_3_ptr = *nlm_temporary_3; int mean_from[] = { 0, 1, 2, 12, 6, 7, 8 }; int variance_from[] = { 3, 4, 5, 13, 9, 10, 11}; @@ -183,17 +177,11 @@ void DenoisingTask::prefilter_color() int variance_to[] = {11, 12, 13}; int num_color_passes = 3; - storage.temporary_color.alloc_to_device(3*buffer.pass_stride, false); - device_sub_ptr nlm_temporary_1(storage.temporary_color, 0*buffer.pass_stride, buffer.pass_stride); - device_sub_ptr nlm_temporary_2(storage.temporary_color, 1*buffer.pass_stride, buffer.pass_stride); - device_sub_ptr nlm_temporary_3(storage.temporary_color, 2*buffer.pass_stride, buffer.pass_stride); - - nlm_state.temporary_1_ptr = *nlm_temporary_1; - nlm_state.temporary_2_ptr = *nlm_temporary_2; - nlm_state.temporary_3_ptr = *nlm_temporary_3; + device_only_memory<float> temporary_color(device, "denoising temporary color"); + temporary_color.alloc_to_device(3*buffer.pass_stride, false); for(int pass = 0; pass < num_color_passes; pass++) { - device_sub_ptr color_pass(storage.temporary_color, pass*buffer.pass_stride, buffer.pass_stride); + device_sub_ptr color_pass(temporary_color, pass*buffer.pass_stride, buffer.pass_stride); device_sub_ptr color_var_pass(buffer.mem, variance_to[pass]*buffer.pass_stride, buffer.pass_stride); functions.get_feature(mean_from[pass], variance_from[pass], *color_pass, *color_var_pass); } @@ -201,9 +189,7 @@ void DenoisingTask::prefilter_color() device_sub_ptr depth_pass (buffer.mem, 0, buffer.pass_stride); device_sub_ptr color_var_pass(buffer.mem, variance_to[0]*buffer.pass_stride, 3*buffer.pass_stride); device_sub_ptr output_pass (buffer.mem, mean_to[0]*buffer.pass_stride, 3*buffer.pass_stride); - functions.detect_outliers(storage.temporary_color.device_pointer, *color_var_pass, *depth_pass, *output_pass); - - storage.temporary_color.free(); + functions.detect_outliers(temporary_color.device_pointer, *color_var_pass, *depth_pass, *output_pass); } void DenoisingTask::construct_transform() @@ -219,14 +205,6 @@ void DenoisingTask::construct_transform() void DenoisingTask::reconstruct() { - - device_only_memory<float> temporary_1(device, "Denoising NLM temporary 1"); - device_only_memory<float> temporary_2(device, "Denoising NLM temporary 2"); - temporary_1.alloc_to_device(buffer.pass_stride, false); - temporary_2.alloc_to_device(buffer.pass_stride, false); - reconstruction_state.tem @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org https://lists.blender.org/mailman/listinfo/bf-blender-cvs