From 05274ca82971332866d94bac07c843aa2ae97f80 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 28 Apr 2020 20:27:03 +0200 Subject: Fix T75432: Cycles progressive refine render slow with denoising data Only perform denoising prefilter for the last sample, not every sample. --- intern/cycles/render/session.cpp | 85 +++++++++++++++++++++++----------------- intern/cycles/render/session.h | 6 ++- intern/cycles/render/tile.cpp | 4 +- intern/cycles/render/tile.h | 2 +- 4 files changed, 57 insertions(+), 40 deletions(-) (limited to 'intern') diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 58bcc7ccdfb..f7df81a0601 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -293,14 +293,12 @@ void Session::run_gpu() * reset and draw in between */ thread_scoped_lock buffers_lock(buffers_mutex); - /* avoid excessive denoising in viewport after reaching a certain amount of samples */ - bool need_denoise = tile_manager.schedule_denoising || tile_manager.state.sample < 20 || - (time_dt() - last_display_time) >= params.progressive_update_timeout; - /* update status and timing */ update_status_time(); /* render */ + bool delayed_denoise = false; + const bool need_denoise = render_need_denoise(delayed_denoise); render(need_denoise); device->task_wait(); @@ -311,7 +309,7 @@ void Session::run_gpu() /* update status and timing */ update_status_time(); - gpu_need_display_buffer_update = need_denoise || !params.run_denoising; + gpu_need_display_buffer_update = !delayed_denoise; gpu_draw_ready = true; progress.set_update(); @@ -477,7 +475,7 @@ void Session::update_tile_sample(RenderTile &rtile) update_status_time(); } -void Session::release_tile(RenderTile &rtile) +void Session::release_tile(RenderTile &rtile, const bool need_denoise) { thread_scoped_lock tile_lock(tile_mutex); @@ -485,7 +483,7 @@ void Session::release_tile(RenderTile &rtile) bool delete_tile; - if (tile_manager.finish_tile(rtile.tile_index, delete_tile)) { + if (tile_manager.finish_tile(rtile.tile_index, need_denoise, delete_tile)) { if (write_render_tile_cb && params.progressive_refine == false) { write_render_tile_cb(rtile); } @@ -687,21 +685,19 @@ void Session::run_cpu() * reset and draw in between */ thread_scoped_lock buffers_lock(buffers_mutex); - /* avoid excessive denoising in viewport after reaching a certain amount of samples */ - bool need_denoise = tile_manager.schedule_denoising || tile_manager.state.sample < 20 || - (time_dt() - last_display_time) >= params.progressive_update_timeout; - /* update status and timing */ update_status_time(); /* render */ + bool delayed_denoise = false; + const bool need_denoise = render_need_denoise(delayed_denoise); render(need_denoise); /* update status and timing */ update_status_time(); if (!params.background) - need_copy_to_display_buffer = need_denoise || !params.run_denoising; + need_copy_to_display_buffer = !delayed_denoise; if (!device->error_message().empty()) progress.set_error(device->error_message()); @@ -1083,7 +1079,46 @@ void Session::update_status_time(bool show_pause, bool show_done) progress.set_status(status, substatus); } -void Session::render(bool with_denoising) +bool Session::render_need_denoise(bool &delayed) +{ + delayed = false; + + /* Denoising enabled? */ + if (!params.run_denoising) { + return false; + } + + if (params.background) { + /* Background render, only denoise when rendering the last sample. */ + return tile_manager.done(); + } + + /* Viewport render. */ + + /* It can happen that denoising was already enabled, but the scene still needs an update. */ + if (scene->film->need_update || !scene->film->denoising_data_offset) { + return false; + } + + /* Do not denoise until the sample at which denoising should start is reached. */ + if (tile_manager.state.sample < params.denoising_start_sample) { + return false; + } + + /* Cannot denoise with resolution divider and separate denoising devices. + * It breaks the copy in 'MultiDevice::map_neighbor_tiles' (which operates on + * the full buffer dimensions and not the scaled ones). */ + if (!params.device.denoising_devices.empty() && tile_manager.state.resolution_divider > 1) { + return false; + } + + /* Avoid excessive denoising in viewport after reaching a certain amount of samples. */ + delayed = (tile_manager.state.sample >= 20 && + (time_dt() - last_display_time) < params.progressive_update_timeout); + return !delayed; +} + +void Session::render(bool need_denoise) { if (buffers && tile_manager.state.sample == tile_manager.range_start_sample) { /* Clear buffers. */ @@ -1098,7 +1133,7 @@ void Session::render(bool with_denoising) DeviceTask task(DeviceTask::RENDER); task.acquire_tile = function_bind(&Session::acquire_tile, this, _2, _1, _3); - task.release_tile = function_bind(&Session::release_tile, this, _1); + task.release_tile = function_bind(&Session::release_tile, this, _1, need_denoise); task.map_neighbor_tiles = function_bind(&Session::map_neighbor_tiles, this, _1, _2); task.unmap_neighbor_tiles = function_bind(&Session::unmap_neighbor_tiles, this, _1, _2); task.get_cancel = function_bind(&Progress::get_cancel, &this->progress); @@ -1115,27 +1150,7 @@ void Session::render(bool with_denoising) /* Acquire render tiles by default. */ task.tile_types = RenderTile::PATH_TRACE; - with_denoising = params.run_denoising && with_denoising; - if (with_denoising) { - /* Do not denoise viewport until the sample at which denoising should start is reached. */ - if (!params.background && tile_manager.state.sample < params.denoising_start_sample) { - with_denoising = false; - } - - /* Cannot denoise with resolution divider and separate denoising devices. - * It breaks the copy in 'MultiDevice::map_neighbor_tiles' (which operates on the full buffer - * dimensions and not the scaled ones). */ - if (!params.device.denoising_devices.empty() && tile_manager.state.resolution_divider > 1) { - with_denoising = false; - } - - /* It can happen that denoising was already enabled, but the scene still needs an update. */ - if (scene->film->need_update || !scene->film->denoising_data_offset) { - with_denoising = false; - } - } - - if (with_denoising) { + if (need_denoise) { task.denoising = params.denoising; task.pass_stride = scene->film->pass_stride; diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index 61970d87e9c..f06952e8020 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -186,7 +186,7 @@ class Session { void update_status_time(bool show_pause = false, bool show_done = false); - void render(bool with_denoising); + void render(bool use_denoise); void copy_to_display_buffer(int sample); void reset_(BufferParams ¶ms, int samples); @@ -199,9 +199,11 @@ class Session { bool draw_gpu(BufferParams ¶ms, DeviceDrawParams &draw_params); void reset_gpu(BufferParams ¶ms, int samples); + bool render_need_denoise(bool &delayed); + bool acquire_tile(RenderTile &tile, Device *tile_device, uint tile_types); void update_tile_sample(RenderTile &tile); - void release_tile(RenderTile &tile); + void release_tile(RenderTile &tile, const bool need_denoise); void map_neighbor_tiles(RenderTile *tiles, Device *tile_device); void unmap_neighbor_tiles(RenderTile *tiles, Device *tile_device); diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp index 1480b6d1aab..375c9fd8e09 100644 --- a/intern/cycles/render/tile.cpp +++ b/intern/cycles/render/tile.cpp @@ -441,13 +441,13 @@ bool TileManager::check_neighbor_state(int index, Tile::State min_state) /* Returns whether the tile should be written (and freed if no denoising is used) instead of * updating. */ -bool TileManager::finish_tile(int index, bool &delete_tile) +bool TileManager::finish_tile(const int index, const bool need_denoise, bool &delete_tile) { delete_tile = false; switch (state.tiles[index].state) { case Tile::RENDER: { - if (!schedule_denoising) { + if (!(schedule_denoising && need_denoise)) { state.tiles[index].state = Tile::DONE; delete_tile = !progressive; return true; diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h index 9fb9c1ca782..4858a275d5c 100644 --- a/intern/cycles/render/tile.h +++ b/intern/cycles/render/tile.h @@ -107,7 +107,7 @@ class TileManager { void set_samples(int num_samples); bool next(); bool next_tile(Tile *&tile, int device, uint tile_types); - bool finish_tile(int index, bool &delete_tile); + bool finish_tile(const int index, const bool need_denoise, bool &delete_tile); bool done(); bool has_tiles(); -- cgit v1.2.3