diff options
24 files changed, 475 insertions, 245 deletions
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index b7e9b1511ec..061e3784b0d 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -182,10 +182,20 @@ enum_aov_types = ( ('COLOR', "Color", "Write a Color pass", 1), ) -enum_viewport_denoising = ( - ('NONE', "None", "Disable viewport denoising", 0), - ('OPTIX', "OptiX AI-Accelerated", "Use the OptiX denoiser running on the GPU (requires at least one compatible OptiX device)", 1), -) +def enum_optix_denoiser(self, context): + if not context or bool(context.preferences.addons[__package__].preferences.get_devices_for_type('OPTIX')): + return [('OPTIX', "OptiX", "Use the OptiX AI denoiser with GPU acceleration, only available on NVIDIA GPUs", 2)] + return [] + +def enum_preview_denoiser(self, context): + items = [('AUTO', "Auto", "Use the fastest available denoiser for viewport rendering", 0)] + items += enum_optix_denoiser(self, context) + return items + +def enum_denoiser(self, context): + items = [('NLM', "NLM", "Cycles native non-local means denoiser, running on any compute device", 1)] + items += enum_optix_denoiser(self, context) + return items enum_denoising_optix_input_passes = ( ('RGB', "Color", "Use only color as input", 1), @@ -224,11 +234,29 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): description="Pause all viewport preview renders", default=False, ) - preview_denoising: EnumProperty( - name="Viewport Denoising", - description="Denoise the image after each preview update with the selected denoiser engine", - items=enum_viewport_denoising, - default='NONE', + + use_denoising: BoolProperty( + name="Use Denoising", + description="Denoise the rendered image", + default=False, + ) + use_preview_denoising: BoolProperty( + name="Use Viewport Denoising", + description="Denoise the image in the 3D viewport", + default=False, + ) + + denoiser: EnumProperty( + name="Denoiser", + description="Denoise the image with the selected denoiser", + items=enum_denoiser, + default=1, + ) + preview_denoiser: EnumProperty( + name="Viewport Denoiser", + description="Denoise the image after each preview update with the selected denoiser", + items=enum_preview_denoiser, + default=0, ) use_square_samples: BoolProperty( @@ -244,7 +272,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): default=128, ) preview_samples: IntProperty( - name="Preview Samples", + name="Viewport Samples", description="Number of samples to render in the viewport, unlimited if 0", min=0, max=(1 << 24), default=32, @@ -464,7 +492,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): subtype='PIXEL' ) preview_dicing_rate: FloatProperty( - name="Preview Dicing Rate", + name="Viewport Dicing Rate", description="Size of a micropolygon in pixels during preview render", min=0.1, max=1000.0, soft_min=0.5, default=8.0, @@ -1330,7 +1358,7 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup): use_denoising: BoolProperty( name="Use Denoising", description="Denoise the rendered image", - default=False, + default=True, update=update_render_passes, ) denoising_diffuse_direct: BoolProperty( @@ -1400,12 +1428,6 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup): default=0, ) - use_optix_denoising: BoolProperty( - name="OptiX AI-Accelerated", - description="Use the OptiX denoiser to denoise the rendered image", - default=False, - update=update_render_passes, - ) denoising_optix_input_passes: EnumProperty( name="Input Passes", description="Passes handed over to the OptiX denoiser (this can have different effects on the denoised image)", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 85da1a17c2b..e689ec90983 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -112,10 +112,6 @@ def show_device_active(context): return True return context.preferences.addons[__package__].preferences.has_active_device() -def show_optix_denoising(context): - # OptiX AI denoiser can be used when at least one device supports OptiX - return bool(context.preferences.addons[__package__].preferences.get_devices_for_type('OPTIX')) - def draw_samples_info(layout, context): cscene = context.scene.cycles @@ -190,11 +186,6 @@ class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel): col.prop(cscene, "aa_samples", text="Render") col.prop(cscene, "preview_aa_samples", text="Viewport") - # Viewport denoising is currently only supported with OptiX - if show_optix_denoising(context): - col = layout.column() - col.prop(cscene, "preview_denoising") - if not use_branched_path(context): draw_samples_info(layout, context) @@ -256,6 +247,39 @@ class CYCLES_RENDER_PT_sampling_adaptive(CyclesButtonsPanel, Panel): col.prop(cscene, "adaptive_threshold", text="Noise Threshold") col.prop(cscene, "adaptive_min_samples", text="Min Samples") + +class CYCLES_RENDER_PT_sampling_denoising(CyclesButtonsPanel, Panel): + bl_label = "Denoising" + bl_parent_id = "CYCLES_RENDER_PT_sampling" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + cscene = scene.cycles + + heading = layout.column(align=True, heading="Render") + row = heading.row(align=True) + row.prop(cscene, "use_denoising", text="") + sub = row.row() + sub.active = cscene.use_denoising + sub.prop(cscene, "denoiser", text="") + + heading = layout.column(align=True, heading="Viewport") + row = heading.row(align=True) + row.prop(cscene, "use_preview_denoising", text="") + sub = row.row() + sub.active = cscene.use_preview_denoising + sub.prop(cscene, "preview_denoiser", text="") + + sub = heading.row(align=True) + sub.active = cscene.use_preview_denoising + sub.prop(cscene, "preview_denoising_start_sample", text="Start Sample") + + class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel): bl_label = "Advanced" bl_parent_id = "CYCLES_RENDER_PT_sampling" @@ -730,11 +754,6 @@ class CYCLES_RENDER_PT_performance_viewport(CyclesButtonsPanel, Panel): col.prop(rd, "preview_pixel_size", text="Pixel Size") col.prop(cscene, "preview_start_resolution", text="Start Pixels") - if show_optix_denoising(context): - sub = col.row(align=True) - sub.active = cscene.preview_denoising != 'NONE' - sub.prop(cscene, "preview_denoising_start_sample", text="Denoising Start Sample") - class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel): bl_label = "Filter" @@ -957,12 +976,17 @@ class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel): bl_context = "view_layer" bl_options = {'DEFAULT_CLOSED'} + @classmethod + def poll(cls, context): + cscene = context.scene.cycles + return CyclesButtonsPanel.poll(context) and cscene.use_denoising + def draw_header(self, context): scene = context.scene view_layer = context.view_layer cycles_view_layer = view_layer.cycles - layout = self.layout + layout = self.layout layout.prop(cycles_view_layer, "use_denoising", text="") def draw(self, context): @@ -973,18 +997,15 @@ class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel): scene = context.scene view_layer = context.view_layer cycles_view_layer = view_layer.cycles + denoiser = scene.cycles.denoiser - layout.active = cycles_view_layer.use_denoising + layout.active = denoiser != 'NONE' and cycles_view_layer.use_denoising col = layout.column() - if show_optix_denoising(context): - col.prop(cycles_view_layer, "use_optix_denoising") - col.separator(factor=2.0) - - if cycles_view_layer.use_optix_denoising: - col.prop(cycles_view_layer, "denoising_optix_input_passes") - return + if denoiser == 'OPTIX': + col.prop(cycles_view_layer, "denoising_optix_input_passes") + return col.prop(cycles_view_layer, "denoising_radius", text="Radius") @@ -2237,6 +2258,7 @@ classes = ( CYCLES_RENDER_PT_sampling, CYCLES_RENDER_PT_sampling_sub_samples, CYCLES_RENDER_PT_sampling_adaptive, + CYCLES_RENDER_PT_sampling_denoising, CYCLES_RENDER_PT_sampling_advanced, CYCLES_RENDER_PT_light_paths, CYCLES_RENDER_PT_light_paths_max_bounces, diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index 40a1a2c2edc..d9c63bec737 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -873,7 +873,8 @@ BufferParams BlenderSync::get_buffer_params(BL::Scene &b_scene, BL::RegionView3D &b_rv3d, Camera *cam, int width, - int height) + int height, + const bool use_denoiser) { BufferParams params; bool use_border = false; @@ -907,8 +908,7 @@ BufferParams BlenderSync::get_buffer_params(BL::Scene &b_scene, PassType display_pass = update_viewport_display_passes(b_v3d, params.passes); /* Can only denoise the combined image pass */ - params.denoising_data_pass = display_pass == PASS_COMBINED && - update_viewport_display_denoising(b_v3d, b_scene); + params.denoising_data_pass = display_pass == PASS_COMBINED && use_denoiser; return params; } diff --git a/intern/cycles/blender/blender_device.cpp b/intern/cycles/blender/blender_device.cpp index ac52948806c..fb9ab9e8c97 100644 --- a/intern/cycles/blender/blender_device.cpp +++ b/intern/cycles/blender/blender_device.cpp @@ -21,13 +21,6 @@ CCL_NAMESPACE_BEGIN -enum DenoiserType { - DENOISER_NONE = 0, - DENOISER_OPTIX = 1, - - DENOISER_NUM -}; - enum ComputeDevice { COMPUTE_DEVICE_CPU = 0, COMPUTE_DEVICE_CUDA = 1, @@ -120,49 +113,6 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen } } - /* Ensure there is an OptiX device when using the OptiX denoiser. */ - bool use_optix_denoising = get_enum(cscene, "preview_denoising", DENOISER_NUM, DENOISER_NONE) == - DENOISER_OPTIX && - !background; - BL::Scene::view_layers_iterator b_view_layer; - for (b_scene.view_layers.begin(b_view_layer); b_view_layer != b_scene.view_layers.end(); - ++b_view_layer) { - PointerRNA crl = RNA_pointer_get(&b_view_layer->ptr, "cycles"); - if (get_boolean(crl, "use_optix_denoising")) { - use_optix_denoising = true; - } - } - - if (use_optix_denoising && device.type != DEVICE_OPTIX) { - vector<DeviceInfo> optix_devices = Device::available_devices(DEVICE_MASK_OPTIX); - if (!optix_devices.empty()) { - /* Convert to a special multi device with separate denoising devices. */ - if (device.multi_devices.empty()) { - device.multi_devices.push_back(device); - } - - /* Try to use the same physical devices for denoising. */ - for (const DeviceInfo &cuda_device : device.multi_devices) { - if (cuda_device.type == DEVICE_CUDA) { - for (const DeviceInfo &optix_device : optix_devices) { - if (cuda_device.num == optix_device.num) { - device.id += optix_device.id; - device.denoising_devices.push_back(optix_device); - break; - } - } - } - } - - if (device.denoising_devices.empty()) { - /* Simply use the first available OptiX device. */ - const DeviceInfo optix_device = optix_devices.front(); - device.id += optix_device.id; /* Uniquely identify this special multi device. */ - device.denoising_devices.push_back(optix_device); - } - } - } - return device; } diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index dbe87ce2b13..2874ccb6470 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -157,8 +157,14 @@ void BlenderSession::create_session() } /* set buffer parameters */ - BufferParams buffer_params = BlenderSync::get_buffer_params( - b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height); + BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, + b_render, + b_v3d, + b_rv3d, + scene->camera, + width, + height, + session_params.denoising.use); session->reset(buffer_params, session_params.samples); b_engine.use_highlight_tiles(session_params.progressive_refine == false); @@ -239,8 +245,14 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL); BL::RegionView3D b_null_region_view3d(PointerRNA_NULL); - BufferParams buffer_params = BlenderSync::get_buffer_params( - b_scene, b_render, b_null_space_view3d, b_null_region_view3d, scene->camera, width, height); + BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, + b_render, + b_null_space_view3d, + b_null_region_view3d, + scene->camera, + width, + height, + session_params.denoising.use); session->reset(buffer_params, session_params.samples); b_engine.use_highlight_tiles(session_params.progressive_refine == false); @@ -468,14 +480,19 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_) session->update_render_tile_cb = function_bind( &BlenderSession::update_render_tile, this, _1, _2); + BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); + /* get buffer parameters */ SessionParams session_params = BlenderSync::get_session_params( - b_engine, b_userpref, b_scene, background); - BufferParams buffer_params = BlenderSync::get_buffer_params( - b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height); - - /* render each layer */ - BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); + b_engine, b_userpref, b_scene, background, b_view_layer); + BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, + b_render, + b_v3d, + b_rv3d, + scene->camera, + width, + height, + session_params.denoising.use); /* temporary render result to find needed passes and views */ BL::RenderResult b_rr = begin_render_result( @@ -485,35 +502,26 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_) BL::RenderLayer b_rlay = *b_single_rlay; b_rlay_name = b_view_layer.name(); - /* add passes */ - vector<Pass> passes = sync->sync_render_passes( - b_rlay, b_view_layer, session_params.adaptive_sampling); - buffer_params.passes = passes; + /* Update denoising parameters. */ + session->set_denoising(session_params.denoising); - PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles"); - bool use_denoising = get_boolean(crl, "use_denoising"); - bool use_optix_denoising = get_boolean(crl, "use_optix_denoising"); - bool write_denoising_passes = get_boolean(crl, "denoising_store_passes"); + bool use_denoising = session_params.denoising.use; + bool store_denoising_passes = session_params.denoising.store_passes; - buffer_params.denoising_data_pass = use_denoising || write_denoising_passes; + buffer_params.denoising_data_pass = use_denoising || store_denoising_passes; buffer_params.denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES); - buffer_params.denoising_prefiltered_pass = write_denoising_passes && !use_optix_denoising; - - session->params.run_denoising = use_denoising || write_denoising_passes; - session->params.full_denoising = use_denoising && !use_optix_denoising; - session->params.optix_denoising = use_denoising && use_optix_denoising; - session->params.write_denoising_passes = write_denoising_passes && !use_optix_denoising; - session->params.denoising.radius = get_int(crl, "denoising_radius"); - session->params.denoising.strength = get_float(crl, "denoising_strength"); - session->params.denoising.feature_strength = get_float(crl, "denoising_feature_strength"); - session->params.denoising.relative_pca = get_boolean(crl, "denoising_relative_pca"); - session->params.denoising.optix_input_passes = get_enum(crl, "denoising_optix_input_passes"); - session->tile_manager.schedule_denoising = session->params.run_denoising; + buffer_params.denoising_prefiltered_pass = store_denoising_passes && + session_params.denoising.type == DENOISER_NLM; scene->film->denoising_data_pass = buffer_params.denoising_data_pass; scene->film->denoising_clean_pass = buffer_params.denoising_clean_pass; scene->film->denoising_prefiltered_pass = buffer_params.denoising_prefiltered_pass; + /* Add passes */ + vector<Pass> passes = sync->sync_render_passes( + b_rlay, b_view_layer, session_params.adaptive_sampling, session_params.denoising); + buffer_params.passes = passes; + scene->film->pass_alpha_threshold = b_view_layer.pass_alpha_threshold(); scene->film->tag_passes_update(scene, passes); scene->film->tag_update(scene); @@ -798,7 +806,7 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_) /* increase samples, but never decrease */ session->set_samples(session_params.samples); - session->set_denoising_start_sample(session_params.denoising_start_sample); + session->set_denoising_start_sample(session_params.denoising.start_sample); session->set_pause(session_pause); /* copy recalc flags, outside of mutex so we can decide to do the real @@ -830,22 +838,24 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_) sync->sync_camera(b_render, b_camera_override, width, height, ""); /* get buffer parameters */ - BufferParams buffer_params = BlenderSync::get_buffer_params( - b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height); - - if (session_params.device.type != DEVICE_OPTIX && - session_params.device.denoising_devices.empty()) { - /* cannot use OptiX denoising when it is not supported by the device. */ - buffer_params.denoising_data_pass = false; - } - else { - session->set_denoising(buffer_params.denoising_data_pass, true); + BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, + b_render, + b_v3d, + b_rv3d, + scene->camera, + width, + height, + session_params.denoising.use); + + if (!buffer_params.denoising_data_pass) { + session_params.denoising.use = false; } + session->set_denoising(session_params.denoising); + + /* Update film if denoising data was enabled or disabled. */ if (scene->film->denoising_data_pass != buffer_params.denoising_data_pass) { scene->film->denoising_data_pass = buffer_params.denoising_data_pass; - - /* Force a scene and session reset below. */ scene->film->tag_update(scene); } @@ -916,8 +926,14 @@ bool BlenderSession::draw(int w, int h) if (reset) { SessionParams session_params = BlenderSync::get_session_params( b_engine, b_userpref, b_scene, background); - BufferParams buffer_params = BlenderSync::get_buffer_params( - b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height); + BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, + b_render, + b_v3d, + b_rv3d, + scene->camera, + width, + height, + session_params.denoising.use); bool session_pause = BlenderSync::get_session_pause(b_scene, background); if (session_pause == false) { @@ -934,8 +950,14 @@ bool BlenderSession::draw(int w, int h) update_status_progress(); /* draw */ - BufferParams buffer_params = BlenderSync::get_buffer_params( - b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height); + BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, + b_render, + b_v3d, + b_rv3d, + scene->camera, + width, + height, + session->params.denoising.use); DeviceDrawParams draw_params; if (session->params.display_buffer_linear) { diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index b40c8434395..aed92cf1376 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -537,7 +537,8 @@ int BlenderSync::get_denoising_pass(BL::RenderPass &b_pass) vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_view_layer, - bool adaptive_sampling) + bool adaptive_sampling, + const DenoiseParams &denoising) { vector<Pass> passes; @@ -554,16 +555,13 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, Pass::add(pass_type, passes, b_pass.name().c_str()); } - PointerRNA crp = RNA_pointer_get(&b_view_layer.ptr, "cycles"); - bool use_denoising = get_boolean(crp, "use_denoising"); - bool use_optix_denoising = get_boolean(crp, "use_optix_denoising"); - bool write_denoising_passes = get_boolean(crp, "denoising_store_passes"); + PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles"); scene->film->denoising_flags = 0; - if (use_denoising || write_denoising_passes) { - if (!use_optix_denoising) { + if (denoising.use || denoising.store_passes) { + if (denoising.type == DENOISER_NLM) { #define MAP_OPTION(name, flag) \ - if (!get_boolean(crp, name)) \ + if (!get_boolean(crl, name)) \ scene->film->denoising_flags |= flag; MAP_OPTION("denoising_diffuse_direct", DENOISING_CLEAN_DIFFUSE_DIR); MAP_OPTION("denoising_diffuse_indirect", DENOISING_CLEAN_DIFFUSE_IND); @@ -576,11 +574,11 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str()); } - if (write_denoising_passes) { + if (denoising.store_passes) { b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str()); b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str()); b_engine.add_pass("Denoising Depth", 1, "Z", b_view_layer.name().c_str()); - if (!use_optix_denoising) { + if (denoising.type == DENOISER_NLM) { b_engine.add_pass("Denoising Shadowing", 1, "X", b_view_layer.name().c_str()); b_engine.add_pass("Denoising Variance", 3, "RGB", b_view_layer.name().c_str()); b_engine.add_pass("Denoising Intensity", 1, "X", b_view_layer.name().c_str()); @@ -592,46 +590,46 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, } #ifdef __KERNEL_DEBUG__ - if (get_boolean(crp, "pass_debug_bvh_traversed_nodes")) { + if (get_boolean(crl, "pass_debug_bvh_traversed_nodes")) { b_engine.add_pass("Debug BVH Traversed Nodes", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_BVH_TRAVERSED_NODES, passes, "Debug BVH Traversed Nodes"); } - if (get_boolean(crp, "pass_debug_bvh_traversed_instances")) { + if (get_boolean(crl, "pass_debug_bvh_traversed_instances")) { b_engine.add_pass("Debug BVH Traversed Instances", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_BVH_TRAVERSED_INSTANCES, passes, "Debug BVH Traversed Instances"); } - if (get_boolean(crp, "pass_debug_bvh_intersections")) { + if (get_boolean(crl, "pass_debug_bvh_intersections")) { b_engine.add_pass("Debug BVH Intersections", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_BVH_INTERSECTIONS, passes, "Debug BVH Intersections"); } - if (get_boolean(crp, "pass_debug_ray_bounces")) { + if (get_boolean(crl, "pass_debug_ray_bounces")) { b_engine.add_pass("Debug Ray Bounces", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_RAY_BOUNCES, passes, "Debug Ray Bounces"); } #endif - if (get_boolean(crp, "pass_debug_render_time")) { + if (get_boolean(crl, "pass_debug_render_time")) { b_engine.add_pass("Debug Render Time", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_RENDER_TIME, passes, "Debug Render Time"); } - if (get_boolean(crp, "pass_debug_sample_count")) { + if (get_boolean(crl, "pass_debug_sample_count")) { b_engine.add_pass("Debug Sample Count", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_SAMPLE_COUNT, passes, "Debug Sample Count"); } - if (get_boolean(crp, "use_pass_volume_direct")) { + if (get_boolean(crl, "use_pass_volume_direct")) { b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str()); Pass::add(PASS_VOLUME_DIRECT, passes, "VolumeDir"); } - if (get_boolean(crp, "use_pass_volume_indirect")) { + if (get_boolean(crl, "use_pass_volume_indirect")) { b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str()); Pass::add(PASS_VOLUME_INDIRECT, passes, "VolumeInd"); } /* Cryptomatte stores two ID/weight pairs per RGBA layer. * User facing parameter is the number of pairs. */ - int crypto_depth = divide_up(min(16, get_int(crp, "pass_crypto_depth")), 2); + int crypto_depth = divide_up(min(16, get_int(crl, "pass_crypto_depth")), 2); scene->film->cryptomatte_depth = crypto_depth; scene->film->cryptomatte_passes = CRYPT_NONE; - if (get_boolean(crp, "use_pass_crypto_object")) { + if (get_boolean(crl, "use_pass_crypto_object")) { for (int i = 0; i < crypto_depth; i++) { string passname = cryptomatte_prefix + string_printf("Object%02d", i); b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); @@ -640,7 +638,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_OBJECT); } - if (get_boolean(crp, "use_pass_crypto_material")) { + if (get_boolean(crl, "use_pass_crypto_material")) { for (int i = 0; i < crypto_depth; i++) { string passname = cryptomatte_prefix + string_printf("Material%02d", i); b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); @@ -649,7 +647,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_MATERIAL); } - if (get_boolean(crp, "use_pass_crypto_asset")) { + if (get_boolean(crl, "use_pass_crypto_asset")) { for (int i = 0; i < crypto_depth; i++) { string passname = cryptomatte_prefix + string_printf("Asset%02d", i); b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); @@ -658,19 +656,19 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_ASSET); } - if (get_boolean(crp, "pass_crypto_accurate") && scene->film->cryptomatte_passes != CRYPT_NONE) { + if (get_boolean(crl, "pass_crypto_accurate") && scene->film->cryptomatte_passes != CRYPT_NONE) { scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_ACCURATE); } if (adaptive_sampling) { Pass::add(PASS_ADAPTIVE_AUX_BUFFER, passes); - if (!get_boolean(crp, "pass_debug_sample_count")) { + if (!get_boolean(crl, "pass_debug_sample_count")) { Pass::add(PASS_SAMPLE_COUNT, passes); } } - RNA_BEGIN (&crp, b_aov, "aovs") { + RNA_BEGIN (&crl, b_aov, "aovs") { bool is_color = (get_enum(b_aov, "type") == 1); string name = get_string(b_aov, "name"); @@ -773,7 +771,8 @@ bool BlenderSync::get_session_pause(BL::Scene &b_scene, bool background) SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine, BL::Preferences &b_preferences, BL::Scene &b_scene, - bool background) + bool background, + BL::ViewLayer b_view_layer) { SessionParams params; PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); @@ -851,9 +850,22 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine, params.tile_order = TILE_BOTTOM_TO_TOP; } - /* other parameters */ + /* Denoising */ + params.denoising = get_denoise_params(b_scene, b_view_layer, background); + + if (params.denoising.use) { + /* Add additional denoising devices if we are rendering and denoising + * with different devices. */ + params.device.add_denoising_devices(params.denoising.type); + + /* Check if denoiser is supported by device. */ + if (!(params.device.denoisers & params.denoising.type)) { + params.denoising.use = false; + } + } + + /* Viewport Performance */ params.start_resolution = get_int(cscene, "preview_start_resolution"); - params.denoising_start_sample = get_int(cscene, "preview_denoising_start_sample"); params.pixel_size = b_engine.get_preview_pixel_size(b_scene); /* other parameters */ @@ -906,4 +918,52 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine, return params; } +DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene, + BL::ViewLayer &b_view_layer, + bool background) +{ + DenoiseParams denoising; + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + + if (background) { + /* Final Render Denoising */ + denoising.use = get_boolean(cscene, "use_denoising"); + denoising.type = (DenoiserType)get_enum(cscene, "denoiser", DENOISER_NUM, DENOISER_NONE); + + if (b_view_layer) { + PointerRNA clayer = RNA_pointer_get(&b_view_layer.ptr, "cycles"); + if (!get_boolean(clayer, "use_denoising")) { + denoising.use = false; + } + + denoising.radius = get_int(clayer, "denoising_radius"); + denoising.strength = get_float(clayer, "denoising_strength"); + denoising.feature_strength = get_float(clayer, "denoising_feature_strength"); + denoising.relative_pca = get_boolean(clayer, "denoising_relative_pca"); + denoising.optix_input_passes = get_enum(clayer, "denoising_optix_input_passes"); + + denoising.store_passes = get_boolean(clayer, "denoising_store_passes"); + } + } + else { + /* Viewport Denoising */ + denoising.use = get_boolean(cscene, "use_preview_denoising"); + denoising.type = (DenoiserType)get_enum( + cscene, "preview_denoiser", DENOISER_NUM, DENOISER_NONE); + denoising.start_sample = get_int(cscene, "preview_denoising_start_sample"); + + /* Auto select fastest denoiser. */ + if (denoising.type == DENOISER_NONE) { + if (!Device::available_devices(DEVICE_MASK_OPTIX).empty()) { + denoising.type = DENOISER_OPTIX; + } + else { + denoising.use = false; + } + } + } + + return denoising; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 25032e8d0fa..85789cd00f6 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -75,7 +75,8 @@ class BlenderSync { void sync_view_layer(BL::SpaceView3D &b_v3d, BL::ViewLayer &b_view_layer); vector<Pass> sync_render_passes(BL::RenderLayer &b_render_layer, BL::ViewLayer &b_view_layer, - bool adaptive_sampling); + bool adaptive_sampling, + const DenoiseParams &denoising); void sync_integrator(); void sync_camera(BL::RenderSettings &b_render, BL::Object &b_override, @@ -94,10 +95,12 @@ class BlenderSync { /* get parameters */ static SceneParams get_scene_params(BL::Scene &b_scene, bool background); - static SessionParams get_session_params(BL::RenderEngine &b_engine, - BL::Preferences &b_userpref, - BL::Scene &b_scene, - bool background); + static SessionParams get_session_params( + BL::RenderEngine &b_engine, + BL::Preferences &b_userpref, + BL::Scene &b_scene, + bool background, + BL::ViewLayer b_view_layer = BL::ViewLayer(PointerRNA_NULL)); static bool get_session_pause(BL::Scene &b_scene, bool background); static BufferParams get_buffer_params(BL::Scene &b_scene, BL::RenderSettings &b_render, @@ -105,12 +108,17 @@ class BlenderSync { BL::RegionView3D &b_rv3d, Camera *cam, int width, - int height); + int height, + const bool use_denoiser); static PassType get_pass_type(BL::RenderPass &b_pass); static int get_denoising_pass(BL::RenderPass &b_pass); private: + static DenoiseParams get_denoise_params(BL::Scene &b_scene, + BL::ViewLayer &b_view_layer, + bool background); + /* sync */ void sync_lights(BL::Depsgraph &b_depsgraph, bool update_all); void sync_materials(BL::Depsgraph &b_depsgraph, bool update_all); diff --git a/intern/cycles/blender/blender_viewport.cpp b/intern/cycles/blender/blender_viewport.cpp index 93e84e28032..73ef5f94720 100644 --- a/intern/cycles/blender/blender_viewport.cpp +++ b/intern/cycles/blender/blender_viewport.cpp @@ -61,17 +61,6 @@ const bool BlenderViewportParameters::custom_viewport_parameters() const return !(use_scene_world && use_scene_lights); } -bool BlenderViewportParameters::get_viewport_display_denoising(BL::SpaceView3D &b_v3d, - BL::Scene &b_scene) -{ - bool use_denoising = false; - if (b_v3d) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - use_denoising = get_enum(cscene, "preview_denoising") != 0; - } - return use_denoising; -} - PassType BlenderViewportParameters::get_viewport_display_render_pass(BL::SpaceView3D &b_v3d) { PassType display_pass = PASS_NONE; @@ -83,11 +72,6 @@ PassType BlenderViewportParameters::get_viewport_display_render_pass(BL::SpaceVi return display_pass; } -bool update_viewport_display_denoising(BL::SpaceView3D &b_v3d, BL::Scene &b_scene) -{ - return BlenderViewportParameters::get_viewport_display_denoising(b_v3d, b_scene); -} - PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes) { if (b_v3d) { diff --git a/intern/cycles/blender/blender_viewport.h b/intern/cycles/blender/blender_viewport.h index 3e44e552f1d..7c6c9c4d274 100644 --- a/intern/cycles/blender/blender_viewport.h +++ b/intern/cycles/blender/blender_viewport.h @@ -44,15 +44,11 @@ class BlenderViewportParameters { friend class BlenderSync; public: - /* Get whether to enable denoising data pass in viewport. */ - static bool get_viewport_display_denoising(BL::SpaceView3D &b_v3d, BL::Scene &b_scene); /* Retrieve the render pass that needs to be displayed on the given `SpaceView3D` * When the `b_v3d` parameter is not given `PASS_NONE` will be returned. */ static PassType get_viewport_display_render_pass(BL::SpaceView3D &b_v3d); }; -bool update_viewport_display_denoising(BL::SpaceView3D &b_v3d, BL::Scene &b_scene); - PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes); CCL_NAMESPACE_END diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index 263d3d24b13..73415d5f9c6 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -603,6 +603,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices, info.has_osl = true; info.has_profiling = true; info.has_peer_memory = false; + info.denoisers = DENOISER_ALL; foreach (const DeviceInfo &device, subdevices) { /* Ensure CPU device does not slow down GPU. */ @@ -647,6 +648,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices, info.has_osl &= device.has_osl; info.has_profiling &= device.has_profiling; info.has_peer_memory |= device.has_peer_memory; + info.denoisers &= device.denoisers; } return info; @@ -667,4 +669,43 @@ void Device::free_memory() network_devices.free_memory(); } +/* DeviceInfo */ + +void DeviceInfo::add_denoising_devices(DenoiserType denoiser_type) +{ + assert(denoising_devices.empty()); + + if (denoiser_type == DENOISER_OPTIX && type != DEVICE_OPTIX) { + vector<DeviceInfo> optix_devices = Device::available_devices(DEVICE_MASK_OPTIX); + if (!optix_devices.empty()) { + /* Convert to a special multi device with separate denoising devices. */ + if (multi_devices.empty()) { + multi_devices.push_back(*this); + } + + /* Try to use the same physical devices for denoising. */ + for (const DeviceInfo &cuda_device : multi_devices) { + if (cuda_device.type == DEVICE_CUDA) { + for (const DeviceInfo &optix_device : optix_devices) { + if (cuda_device.num == optix_device.num) { + id += optix_device.id; + denoising_devices.push_back(optix_device); + break; + } + } + } + } + + if (denoising_devices.empty()) { + /* Simply use the first available OptiX device. */ + const DeviceInfo optix_device = optix_devices.front(); + id += optix_device.id; /* Uniquely identify this special multi device. */ + denoising_devices.push_back(optix_device); + } + + denoisers = denoiser_type; + } + } +} + CCL_NAMESPACE_END diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 69f22aeb35c..a5833369a17 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -83,6 +83,7 @@ class DeviceInfo { bool use_split_kernel; /* Use split or mega kernel. */ bool has_profiling; /* Supports runtime collection of profiling info. */ bool has_peer_memory; /* GPU has P2P access to memory of another GPU. */ + DenoiserTypeMask denoisers; /* Supported denoiser types. */ int cpu_threads; vector<DeviceInfo> multi_devices; vector<DeviceInfo> denoising_devices; @@ -101,6 +102,7 @@ class DeviceInfo { use_split_kernel = false; has_profiling = false; has_peer_memory = false; + denoisers = DENOISER_NONE; } bool operator==(const DeviceInfo &info) @@ -110,6 +112,9 @@ class DeviceInfo { (type == info.type && num == info.num && description == info.description)); return id == info.id; } + + /* Add additional devices needed for the specified denoiser. */ + void add_denoising_devices(DenoiserType denoiser_type); }; class DeviceRequestedFeatures { diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index a36c76c852a..1f760a15530 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -943,7 +943,7 @@ class CPUDevice : public Device { } } - void denoise(DenoisingTask &denoising, RenderTile &tile) + void denoise_nlm(DenoisingTask &denoising, RenderTile &tile) { ProfilingHelper profiling(denoising.profiler, PROFILING_DENOISING); @@ -1001,10 +1001,9 @@ class CPUDevice : public Device { } } - RenderTile tile; - DenoisingTask denoising(this, task); - denoising.profiler = &kg->profiler; + DenoisingTask *denoising = NULL; + RenderTile tile; while (task.acquire_tile(this, tile, task.tile_types)) { if (tile.task == RenderTile::PATH_TRACE) { if (use_split_kernel) { @@ -1019,7 +1018,13 @@ class CPUDevice : public Device { render(task, tile, kg); } else if (tile.task == RenderTile::DENOISE) { - denoise(denoising, tile); + if (task.denoising.type == DENOISER_NLM) { + if (denoising == NULL) { + denoising = new DenoisingTask(this, task); + denoising->profiler = &kg->profiler; + } + denoise_nlm(*denoising, tile); + } task.update_progress(&tile, tile.w * tile.h); } @@ -1037,6 +1042,7 @@ class CPUDevice : public Device { kg->~KernelGlobals(); kgbuffer.free(); delete split_kernel; + delete denoising; } void thread_denoise(DeviceTask &task) @@ -1060,7 +1066,7 @@ class CPUDevice : public Device { profiler.add_state(&denoising_profiler_state); denoising.profiler = &denoising_profiler_state; - denoise(denoising, tile); + denoise_nlm(denoising, tile); task.update_progress(&tile, tile.w * tile.h); profiler.remove_state(&denoising_profiler_state); @@ -1344,6 +1350,7 @@ void device_cpu_info(vector<DeviceInfo> &devices) info.has_osl = true; info.has_half_images = true; info.has_profiling = true; + info.denoisers = DENOISER_NLM; devices.insert(devices.begin(), info); } diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 04c04761311..d9ffcceb06e 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -130,6 +130,7 @@ void device_cuda_info(vector<DeviceInfo> &devices) info.has_half_images = (major >= 3); info.has_volume_decoupled = false; info.has_adaptive_stop_per_sample = false; + info.denoisers = DENOISER_NLM; /* Check if the device has P2P access to any other device in the system. */ for (int peer_num = 0; peer_num < count && !info.has_peer_memory; peer_num++) { diff --git a/intern/cycles/device/device_denoising.cpp b/intern/cycles/device/device_denoising.cpp index ac17c02a427..91ebb7c266e 100644 --- a/intern/cycles/device/device_denoising.cpp +++ b/intern/cycles/device/device_denoising.cpp @@ -56,8 +56,8 @@ DenoisingTask::DenoisingTask(Device *device, const DeviceTask &task) tile_info->frames[i] = task.denoising_frames[i - 1]; } - write_passes = task.denoising_write_passes; - do_filter = task.denoising_do_filter; + do_prefilter = task.denoising.store_passes && task.denoising.type == DENOISER_NLM; + do_filter = task.denoising_do_filter && task.denoising.type == DENOISER_NLM; } DenoisingTask::~DenoisingTask() @@ -91,7 +91,7 @@ void DenoisingTask::set_render_buffer(RenderTile *rtiles) target_buffer.stride = rtiles[9].stride; target_buffer.ptr = rtiles[9].buffer; - if (write_passes && rtiles[9].buffers) { + if (do_prefilter && rtiles[9].buffers) { target_buffer.denoising_output_offset = rtiles[9].buffers->params.get_denoising_prefiltered_offset(); } @@ -111,7 +111,7 @@ void DenoisingTask::setup_denoising_buffer() rect = rect_clip(rect, make_int4(tile_info->x[0], tile_info->y[0], tile_info->x[3], tile_info->y[3])); - buffer.use_intensity = write_passes || (tile_info->num_frames > 1); + buffer.use_intensity = do_prefilter || (tile_info->num_frames > 1); buffer.passes = buffer.use_intensity ? 15 : 14; buffer.width = rect.z - rect.x; buffer.stride = align_up(buffer.width, 4); @@ -343,7 +343,7 @@ void DenoisingTask::run_denoising(RenderTile *tile) reconstruct(); } - if (write_passes) { + if (do_prefilter) { write_buffer(); } diff --git a/intern/cycles/device/device_denoising.h b/intern/cycles/device/device_denoising.h index bd1d0193dbd..4c122e981eb 100644 --- a/intern/cycles/device/device_denoising.h +++ b/intern/cycles/device/device_denoising.h @@ -60,7 +60,7 @@ class DenoisingTask { int4 rect; int4 filter_area; - bool write_passes; + bool do_prefilter; bool do_filter; struct DeviceFunctions { diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp index 0933d51f321..8904b517e92 100644 --- a/intern/cycles/device/device_network.cpp +++ b/intern/cycles/device/device_network.cpp @@ -313,6 +313,7 @@ void device_network_info(vector<DeviceInfo> &devices) info.has_volume_decoupled = false; info.has_adaptive_stop_per_sample = false; info.has_osl = false; + info.denoisers = DENOISER_NONE; devices.push_back(info); } diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index 8a0b128697f..39b9ef70192 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -120,6 +120,7 @@ void device_opencl_info(vector<DeviceInfo> &devices) info.use_split_kernel = true; info.has_volume_decoupled = false; info.has_adaptive_stop_per_sample = false; + info.denoisers = DENOISER_NLM; info.id = id; /* Check OpenCL extensions */ diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp index 7aab2c96db4..d4d859e8593 100644 --- a/intern/cycles/device/device_optix.cpp +++ b/intern/cycles/device/device_optix.cpp @@ -721,7 +721,7 @@ class OptiXDevice : public CUDADevice { const CUDAContextScope scope(cuContext); // Choose between OptiX and NLM denoising - if (task.denoising_use_optix) { + if (task.denoising.type == DENOISER_OPTIX) { // Map neighboring tiles onto this device, indices are as following: // Where index 4 is the center tile and index 9 is the target for the result. // 0 1 2 @@ -1561,6 +1561,7 @@ void device_optix_info(const vector<DeviceInfo> &cuda_devices, vector<DeviceInfo info.type = DEVICE_OPTIX; info.id += "_OptiX"; + info.denoisers |= DENOISER_OPTIX; devices.push_back(info); } diff --git a/intern/cycles/device/device_task.h b/intern/cycles/device/device_task.h index 5f675bf7e04..1ad8e0d9485 100644 --- a/intern/cycles/device/device_task.h +++ b/intern/cycles/device/device_task.h @@ -31,8 +31,32 @@ class RenderBuffers; class RenderTile; class Tile; +enum DenoiserType { + DENOISER_NLM = 1, + DENOISER_OPTIX = 2, + DENOISER_NUM, + + DENOISER_NONE = 0, + DENOISER_ALL = ~0, +}; + +typedef int DenoiserTypeMask; + class DenoiseParams { public: + /* Apply denoiser to image. */ + bool use; + /* Output denoising data passes (possibly without applying the denoiser). */ + bool store_passes; + + /* Denoiser type. */ + DenoiserType type; + + /* Viewport start sample. */ + int start_sample; + + /** Native Denoiser **/ + /* Pixel radius for neighboring pixels to take into account. */ int radius; /* Controls neighbor pixel weighting for the denoising filter. */ @@ -46,18 +70,36 @@ class DenoiseParams { int neighbor_frames; /* Clamp the input to the range of +-1e8. Should be enough for any legitimate data. */ bool clamp_input; + + /** Optix Denoiser **/ + /* Passes handed over to the OptiX denoiser (default to color + albedo). */ int optix_input_passes; DenoiseParams() { + use = false; + store_passes = false; + + type = DENOISER_NLM; + radius = 8; strength = 0.5f; feature_strength = 0.5f; relative_pca = false; neighbor_frames = 2; clamp_input = true; + optix_input_passes = 2; + + start_sample = 0; + } + + /* Test if a denoising task needs to run, also to prefilter passes for the native + * denoiser when we are not applying denoising to the combined image. */ + bool need_denoising_task() const + { + return (use || (store_passes && type == DENOISER_NLM)); } }; @@ -116,8 +158,7 @@ class DeviceTask { vector<int> denoising_frames; bool denoising_do_filter; - bool denoising_use_optix; - bool denoising_write_passes; + bool denoising_do_prefilter; int pass_stride; int frame_stride; diff --git a/intern/cycles/render/denoising.cpp b/intern/cycles/render/denoising.cpp index 93815ebfbc4..4055bc4773b 100644 --- a/intern/cycles/render/denoising.cpp +++ b/intern/cycles/render/denoising.cpp @@ -378,8 +378,9 @@ void DenoiseTask::create_task(DeviceTask &task) /* Denoising parameters. */ task.denoising = denoiser->params; - task.denoising_do_filter = true; - task.denoising_write_passes = false; + task.denoising.type = DENOISER_NLM; + task.denoising.use = true; + task.denoising.store_passes = false; task.denoising_from_render = false; task.denoising_frames.resize(neighbor_frames.size()); diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 9d5e57404f0..f11722ac9a9 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -805,7 +805,7 @@ DeviceRequestedFeatures Session::get_requested_device_features() requested_features.use_baking = bake_manager->get_baking(); requested_features.use_integrator_branched = (scene->integrator->method == Integrator::BRANCHED_PATH); - if (params.run_denoising) { + if (params.denoising.use || params.denoising.store_passes) { requested_features.use_denoising = true; requested_features.use_shadow_tricks = true; } @@ -942,24 +942,31 @@ void Session::set_pause(bool pause_) pause_cond.notify_all(); } -void Session::set_denoising(bool denoising, bool optix_denoising) +void Session::set_denoising(const DenoiseParams &denoising) { + const bool need_denoise = denoising.need_denoising_task(); + + if (need_denoise && !(params.device.denoisers & denoising.type)) { + progress.set_error("Denoiser type not supported by compute device"); + return; + } + /* Lock buffers so no denoising operation is triggered while the settings are changed here. */ thread_scoped_lock buffers_lock(buffers_mutex); - - params.run_denoising = denoising; - params.full_denoising = !optix_denoising; - params.optix_denoising = optix_denoising; + params.denoising = denoising; // TODO(pmours): Query the required overlap value for denoising from the device? - tile_manager.slice_overlap = denoising && !params.background ? 64 : 0; - tile_manager.schedule_denoising = denoising && !buffers; + tile_manager.slice_overlap = need_denoise && !params.background ? 64 : 0; + + /* Schedule per tile denoising for final renders if we are either denoising or + * need prefiltered passes for the native denoiser. */ + tile_manager.schedule_denoising = need_denoise && !buffers; } void Session::set_denoising_start_sample(int sample) { - if (sample != params.denoising_start_sample) { - params.denoising_start_sample = sample; + if (sample != params.denoising.start_sample) { + params.denoising.start_sample = sample; pause_cond.notify_all(); } @@ -1079,10 +1086,10 @@ void Session::update_status_time(bool show_pause, bool show_done) */ substatus += string_printf(", Sample %d/%d", progress.get_current_sample(), num_samples); } - if (params.full_denoising || params.optix_denoising) { + if (params.denoising.use) { substatus += string_printf(", Denoised %d tiles", progress.get_denoised_tiles()); } - else if (params.run_denoising) { + else if (params.denoising.store_passes && params.denoising.type == DENOISER_NLM) { substatus += string_printf(", Prefiltered %d tiles", progress.get_denoised_tiles()); } } @@ -1111,7 +1118,7 @@ bool Session::render_need_denoise(bool &delayed) delayed = false; /* Denoising enabled? */ - if (!params.run_denoising) { + if (!params.denoising.need_denoising_task()) { return false; } @@ -1128,7 +1135,7 @@ bool Session::render_need_denoise(bool &delayed) } /* Do not denoise until the sample at which denoising should start is reached. */ - if (tile_manager.state.sample < params.denoising_start_sample) { + if (tile_manager.state.sample < params.denoising.start_sample) { return false; } @@ -1179,9 +1186,6 @@ void Session::render(bool need_denoise) task.pass_denoising_clean = scene->film->denoising_clean_offset; task.denoising_from_render = true; - task.denoising_do_filter = params.full_denoising; - task.denoising_use_optix = params.optix_denoising; - task.denoising_write_passes = params.write_denoising_passes; if (tile_manager.schedule_denoising) { /* Acquire denoising tiles during rendering. */ diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index 2707eed5531..0141629762c 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -62,10 +62,6 @@ class SessionParams { bool display_buffer_linear; - bool run_denoising; - bool write_denoising_passes; - bool full_denoising; - bool optix_denoising; DenoiseParams denoising; double cancel_timeout; @@ -94,11 +90,6 @@ class SessionParams { use_profiling = false; - run_denoising = false; - write_denoising_passes = false; - full_denoising = false; - optix_denoising = false; - display_buffer_linear = false; cancel_timeout = 0.1; @@ -125,7 +116,8 @@ class SessionParams { cancel_timeout == params.cancel_timeout && reset_timeout == params.reset_timeout && text_timeout == params.text_timeout && progressive_update_timeout == params.progressive_update_timeout && - tile_order == params.tile_order && shadingsystem == params.shadingsystem); + tile_order == params.tile_order && shadingsystem == params.shadingsystem && + denoising.type == params.denoising.type); } }; @@ -161,7 +153,7 @@ class Session { void reset(BufferParams ¶ms, int samples); void set_pause(bool pause); void set_samples(int samples); - void set_denoising(bool denoising, bool optix_denoising); + void set_denoising(const DenoiseParams &denoising); void set_denoising_start_sample(int sample); bool update_scene(); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 9d948dfd57b..229b5193e9c 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -40,7 +40,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 4 +#define BLENDER_FILE_SUBVERSION 5 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c index ff3d4574561..72ee4c5ec4d 100644 --- a/source/blender/blenloader/intern/versioning_cycles.c +++ b/source/blender/blenloader/intern/versioning_cycles.c @@ -78,22 +78,45 @@ static IDProperty *cycles_properties_from_ID(ID *id) return (idprop) ? IDP_GetPropertyTypeFromGroup(idprop, "cycles", IDP_GROUP) : NULL; } +static IDProperty *cycles_properties_from_view_layer(ViewLayer *view_layer) +{ + IDProperty *idprop = view_layer->id_properties; + return (idprop) ? IDP_GetPropertyTypeFromGroup(idprop, "cycles", IDP_GROUP) : NULL; +} + static float cycles_property_float(IDProperty *idprop, const char *name, float default_value) { IDProperty *prop = IDP_GetPropertyTypeFromGroup(idprop, name, IDP_FLOAT); return (prop) ? IDP_Float(prop) : default_value; } -static float cycles_property_int(IDProperty *idprop, const char *name, int default_value) +static int cycles_property_int(IDProperty *idprop, const char *name, int default_value) { IDProperty *prop = IDP_GetPropertyTypeFromGroup(idprop, name, IDP_INT); return (prop) ? IDP_Int(prop) : default_value; } -static bool cycles_property_boolean(IDProperty *idprop, const char *name, bool default_value) +static void cycles_property_int_set(IDProperty *idprop, const char *name, int value) { IDProperty *prop = IDP_GetPropertyTypeFromGroup(idprop, name, IDP_INT); - return (prop) ? IDP_Int(prop) : default_value; + if (prop) { + IDP_Int(prop) = value; + } + else { + IDPropertyTemplate val = {0}; + val.i = value; + IDP_AddToGroup(idprop, IDP_New(IDP_INT, &val, name)); + } +} + +static bool cycles_property_boolean(IDProperty *idprop, const char *name, bool default_value) +{ + return cycles_property_int(idprop, name, default_value); +} + +static void cycles_property_boolean_set(IDProperty *idprop, const char *name, bool value) +{ + cycles_property_int_set(idprop, name, value); } static void displacement_node_insert(bNodeTree *ntree) @@ -1524,4 +1547,52 @@ void do_versions_after_linking_cycles(Main *bmain) } FOREACH_NODETREE_END; } + + if (!MAIN_VERSION_ATLEAST(bmain, 290, 5)) { + /* New denoiser settings. */ + for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { + IDProperty *cscene = cycles_properties_from_ID(&scene->id); + + /* Check if any view layers had (optix) denoising enabled. */ + bool use_optix = false; + bool use_denoising = false; + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; + view_layer = view_layer->next) { + IDProperty *cview_layer = cycles_properties_from_view_layer(view_layer); + if (cview_layer) { + use_denoising = use_denoising || + cycles_property_boolean(cview_layer, "use_denoising", false); + use_optix = use_optix || + cycles_property_boolean(cview_layer, "use_optix_denoising", false); + } + } + + if (cscene) { + const int DENOISER_NLM = 1; + const int DENOISER_OPTIX = 2; + + /* Enable denoiser if it was enabled for one view layer before. */ + cycles_property_int_set(cscene, "denoiser", (use_optix) ? DENOISER_OPTIX : DENOISER_NLM); + cycles_property_boolean_set(cscene, "use_denoising", use_denoising); + + /* Migrate Optix denoiser to new settings. */ + if (cycles_property_int(cscene, "preview_denoising", 0)) { + cycles_property_boolean_set(cscene, "use_preview_denoising", true); + cycles_property_boolean_set(cscene, "preview_denoiser", DENOISER_OPTIX); + } + } + + /* Enable denoising in all view layer if there was no denoising before, + * so that enabling the scene settings auto enables it for all view layers. */ + if (!use_denoising) { + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; + view_layer = view_layer->next) { + IDProperty *cview_layer = cycles_properties_from_view_layer(view_layer); + if (cview_layer) { + cycles_property_boolean_set(cview_layer, "use_denoising", true); + } + } + } + } + } } |