diff options
Diffstat (limited to 'intern/cycles/render/session.cpp')
-rw-r--r-- | intern/cycles/render/session.cpp | 412 |
1 files changed, 243 insertions, 169 deletions
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 6ea902f4431..0080b1d138a 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -17,24 +17,24 @@ #include <string.h> #include <limits.h> -#include "buffers.h" -#include "camera.h" -#include "device.h" -#include "graph.h" -#include "integrator.h" -#include "mesh.h" -#include "object.h" -#include "scene.h" -#include "session.h" -#include "bake.h" - -#include "util_foreach.h" -#include "util_function.h" -#include "util_logging.h" -#include "util_math.h" -#include "util_opengl.h" -#include "util_task.h" -#include "util_time.h" +#include "render/buffers.h" +#include "render/camera.h" +#include "device/device.h" +#include "render/graph.h" +#include "render/integrator.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/scene.h" +#include "render/session.h" +#include "render/bake.h" + +#include "util/util_foreach.h" +#include "util/util_function.h" +#include "util/util_logging.h" +#include "util/util_math.h" +#include "util/util_opengl.h" +#include "util/util_task.h" +#include "util/util_time.h" CCL_NAMESPACE_BEGIN @@ -46,7 +46,7 @@ Session::Session(const SessionParams& params_) : params(params_), tile_manager(params.progressive, params.samples, params.tile_size, params.start_resolution, params.background == false || params.progressive_refine, params.background, params.tile_order, - max(params.device.multi_devices.size(), 1)), + max(params.device.multi_devices.size(), 1), params.pixel_size), stats() { device_use_gl = ((params.device.type != DEVICE_CPU) && !params.background); @@ -67,10 +67,7 @@ Session::Session(const SessionParams& params_) session_thread = NULL; scene = NULL; - start_time = 0.0; reset_time = 0.0; - preview_time = 0.0; - paused_time = 0.0; last_update_time = 0.0; delayed_reset.do_reset = false; @@ -117,8 +114,9 @@ Session::~Session() } /* clean up */ - foreach(RenderBuffers *buffers, tile_buffers) - delete buffers; + foreach(RenderTile &rtile, render_tiles) + delete rtile.buffers; + tile_manager.free_device(); delete buffers; delete display; @@ -201,12 +199,10 @@ void Session::run_gpu() { bool tiles_written = false; - start_time = time_dt(); reset_time = time_dt(); - paused_time = 0.0; last_update_time = time_dt(); - progress.set_render_start_time(start_time + paused_time); + progress.set_render_start_time(); while(!progress.get_cancel()) { /* advance to next tile */ @@ -233,13 +229,11 @@ void Session::run_gpu() update_status_time(pause, no_tiles); while(1) { - double pause_start = time_dt(); + scoped_timer pause_timer; pause_cond.wait(pause_lock); - paused_time += time_dt() - pause_start; - - if(!params.background) - progress.set_start_time(start_time + paused_time); - progress.set_render_start_time(start_time + paused_time); + if(pause) { + progress.add_skip_time(pause_timer, params.background); + } update_status_time(pause, no_tiles); progress.set_update(); @@ -255,7 +249,9 @@ void Session::run_gpu() if(!no_tiles) { /* update scene */ + scoped_timer update_timer; update_scene(); + progress.add_skip_time(update_timer, params.background); if(!device->error_message().empty()) progress.set_error(device->error_message()); @@ -273,8 +269,8 @@ void Session::run_gpu() /* update status and timing */ update_status_time(); - /* path trace */ - path_trace(); + /* render */ + render(); device->task_wait(); @@ -363,20 +359,22 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile) thread_scoped_lock tile_lock(tile_mutex); /* get next tile from manager */ - Tile tile; + Tile *tile; int device_num = device->device_number(tile_device); if(!tile_manager.next_tile(tile, device_num)) return false; /* fill render tile */ - rtile.x = tile_manager.state.buffer.full_x + tile.x; - rtile.y = tile_manager.state.buffer.full_y + tile.y; - rtile.w = tile.w; - rtile.h = tile.h; + rtile.x = tile_manager.state.buffer.full_x + tile->x; + rtile.y = tile_manager.state.buffer.full_y + tile->y; + rtile.w = tile->w; + rtile.h = tile->h; rtile.start_sample = tile_manager.state.sample; rtile.num_samples = tile_manager.state.num_samples; rtile.resolution = tile_manager.state.resolution_divider; + rtile.tile_index = tile->index; + rtile.task = (tile->state == Tile::DENOISE)? RenderTile::DENOISE: RenderTile::PATH_TRACE; tile_lock.unlock(); @@ -386,56 +384,70 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile) tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride); rtile.buffer = buffers->buffer.device_pointer; - rtile.rng_state = buffers->rng_state.device_pointer; rtile.buffers = buffers; + tile->buffers = buffers; device->map_tile(tile_device, rtile); return true; } - /* fill buffer parameters */ - BufferParams buffer_params = tile_manager.params; - buffer_params.full_x = rtile.x; - buffer_params.full_y = rtile.y; - buffer_params.width = rtile.w; - buffer_params.height = rtile.h; - - buffer_params.get_offset_stride(rtile.offset, rtile.stride); - - RenderBuffers *tilebuffers; + bool store_rtile = false; + if(tile->buffers == NULL) { + /* fill buffer parameters */ + BufferParams buffer_params = tile_manager.params; + buffer_params.full_x = rtile.x; + buffer_params.full_y = rtile.y; + buffer_params.width = rtile.w; + buffer_params.height = rtile.h; + + /* allocate buffers */ + if(params.progressive_refine) { + tile_lock.lock(); + + if(render_tiles.size() == 0) { + RenderTile nulltile; + nulltile.buffers = NULL; + render_tiles.resize(tile_manager.state.num_tiles, nulltile); + } - /* allocate buffers */ - if(params.progressive_refine) { - tile_lock.lock(); + /* In certain circumstances number of tiles in the tile manager could + * be changed. This is not supported by the progressive refine feature. + */ + assert(render_tiles.size() == tile_manager.state.num_tiles); - if(tile_buffers.size() == 0) - tile_buffers.resize(tile_manager.state.num_tiles, NULL); + RenderTile &stored_rtile = render_tiles[tile->index]; + if(stored_rtile.buffers == NULL) { + tile->buffers = new RenderBuffers(tile_device); + tile->buffers->reset(tile_device, buffer_params); + store_rtile = true; + } + else { + assert(rtile.x == stored_rtile.x && + rtile.y == stored_rtile.y && + rtile.w == stored_rtile.w && + rtile.h == stored_rtile.h); + tile_lock.unlock(); + tile->buffers = stored_rtile.buffers; + } + } + else { + tile->buffers = new RenderBuffers(tile_device); - /* In certain circumstances number of tiles in the tile manager could - * be changed. This is not supported by the progressive refine feature. - */ - assert(tile_buffers.size() == tile_manager.state.num_tiles); + tile->buffers->reset(tile_device, buffer_params); + } + } - tilebuffers = tile_buffers[tile.index]; - if(tilebuffers == NULL) { - tilebuffers = new RenderBuffers(tile_device); - tile_buffers[tile.index] = tilebuffers; + tile->buffers->params.get_offset_stride(rtile.offset, rtile.stride); - tilebuffers->reset(tile_device, buffer_params); - } + rtile.buffer = tile->buffers->buffer.device_pointer; + rtile.buffers = tile->buffers; + rtile.sample = 0; + if(store_rtile) { + render_tiles[tile->index] = rtile; tile_lock.unlock(); } - else { - tilebuffers = new RenderBuffers(tile_device); - - tilebuffers->reset(tile_device, buffer_params); - } - - rtile.buffer = tilebuffers->buffer.device_pointer; - rtile.rng_state = tilebuffers->rng_state.device_pointer; - rtile.buffers = tilebuffers; /* this will tag tile as IN PROGRESS in blender-side render pipeline, * which is needed to highlight currently rendering tile before first @@ -454,7 +466,7 @@ void Session::update_tile_sample(RenderTile& rtile) if(params.progressive_refine == false) { /* todo: optimize this by making it thread safe and removing lock */ - update_render_tile_cb(rtile); + update_render_tile_cb(rtile, true); } } @@ -465,18 +477,77 @@ void Session::release_tile(RenderTile& rtile) { thread_scoped_lock tile_lock(tile_mutex); - if(write_render_tile_cb) { - if(params.progressive_refine == false) { - /* todo: optimize this by making it thread safe and removing lock */ - write_render_tile_cb(rtile); + progress.add_finished_tile(rtile.task == RenderTile::DENOISE); - delete rtile.buffers; + bool delete_tile; + + if(tile_manager.finish_tile(rtile.tile_index, delete_tile)) { + if(write_render_tile_cb && params.progressive_refine == false) { + write_render_tile_cb(rtile); + if(delete_tile) { + delete rtile.buffers; + tile_manager.state.tiles[rtile.tile_index].buffers = NULL; + } + } + } + else { + if(update_render_tile_cb && params.progressive_refine == false) { + update_render_tile_cb(rtile, false); } } update_status_time(); } +void Session::map_neighbor_tiles(RenderTile *tiles, Device *tile_device) +{ + thread_scoped_lock tile_lock(tile_mutex); + + int center_idx = tiles[4].tile_index; + assert(tile_manager.state.tiles[center_idx].state == Tile::DENOISE); + BufferParams buffer_params = tile_manager.params; + int4 image_region = make_int4(buffer_params.full_x, buffer_params.full_y, + buffer_params.full_x + buffer_params.width, buffer_params.full_y + buffer_params.height); + + for(int dy = -1, i = 0; dy <= 1; dy++) { + for(int dx = -1; dx <= 1; dx++, i++) { + int px = tiles[4].x + dx*params.tile_size.x; + int py = tiles[4].y + dy*params.tile_size.y; + if(px >= image_region.x && py >= image_region.y && + px < image_region.z && py < image_region.w) { + int tile_index = center_idx + dy*tile_manager.state.tile_stride + dx; + Tile *tile = &tile_manager.state.tiles[tile_index]; + assert(tile->buffers); + + tiles[i].buffer = tile->buffers->buffer.device_pointer; + tiles[i].x = tile_manager.state.buffer.full_x + tile->x; + tiles[i].y = tile_manager.state.buffer.full_y + tile->y; + tiles[i].w = tile->w; + tiles[i].h = tile->h; + tiles[i].buffers = tile->buffers; + + tile->buffers->params.get_offset_stride(tiles[i].offset, tiles[i].stride); + } + else { + tiles[i].buffer = (device_ptr)NULL; + tiles[i].buffers = NULL; + tiles[i].x = clamp(px, image_region.x, image_region.z); + tiles[i].y = clamp(py, image_region.y, image_region.w); + tiles[i].w = tiles[i].h = 0; + } + } + } + + assert(tiles[4].buffers); + device->map_neighbor_tiles(tile_device, tiles); +} + +void Session::unmap_neighbor_tiles(RenderTile *tiles, Device *tile_device) +{ + thread_scoped_lock tile_lock(tile_mutex); + device->unmap_neighbor_tiles(tile_device, tiles); +} + void Session::run_cpu() { bool tiles_written = false; @@ -523,13 +594,11 @@ void Session::run_cpu() update_status_time(pause, no_tiles); while(1) { - double pause_start = time_dt(); + scoped_timer pause_timer; pause_cond.wait(pause_lock); - paused_time += time_dt() - pause_start; - - if(!params.background) - progress.set_start_time(start_time + paused_time); - progress.set_render_start_time(start_time + paused_time); + if(pause) { + progress.add_skip_time(pause_timer, params.background); + } update_status_time(pause, no_tiles); progress.set_update(); @@ -550,7 +619,9 @@ void Session::run_cpu() thread_scoped_lock buffers_lock(buffers_mutex); /* update scene */ + scoped_timer update_timer; update_scene(); + progress.add_skip_time(update_timer, params.background); if(!device->error_message().empty()) progress.set_error(device->error_message()); @@ -561,8 +632,8 @@ void Session::run_cpu() /* update status and timing */ update_status_time(); - /* path trace */ - path_trace(); + /* render */ + render(); /* update status and timing */ update_status_time(); @@ -641,23 +712,33 @@ DeviceRequestedFeatures Session::get_requested_device_features() requested_features.use_patch_evaluation = true; } #endif + if(object->is_shadow_catcher) { + requested_features.use_shadow_tricks = true; + } } BakeManager *bake_manager = scene->bake_manager; requested_features.use_baking = bake_manager->get_baking(); requested_features.use_integrator_branched = (scene->integrator->method == Integrator::BRANCHED_PATH); + requested_features.use_denoising = params.use_denoising; return requested_features; } -void Session::load_kernels() +void Session::load_kernels(bool lock_scene) { - thread_scoped_lock scene_lock(scene->mutex); + thread_scoped_lock scene_lock; + if(lock_scene) { + scene_lock = thread_scoped_lock(scene->mutex); + } + + DeviceRequestedFeatures requested_features = get_requested_device_features(); - if(!kernels_loaded) { + if(!kernels_loaded || loaded_kernel_features.modified(requested_features)) { progress.set_status("Loading render kernels (may take a few minutes the first time)"); - DeviceRequestedFeatures requested_features = get_requested_device_features(); + scoped_timer timer; + VLOG(2) << "Requested features:\n" << requested_features; if(!device->load_kernels(requested_features)) { string message = device->error_message(); @@ -670,7 +751,11 @@ void Session::load_kernels() return; } + progress.add_skip_time(timer, false); + VLOG(1) << "Total time spent loading kernels: " << time_dt() - timer.get_start(); + kernels_loaded = true; + loaded_kernel_features = requested_features; } } @@ -719,14 +804,14 @@ void Session::reset_(BufferParams& buffer_params, int samples) } tile_manager.reset(buffer_params, samples); + progress.reset_sample(); - start_time = time_dt(); - preview_time = 0.0; - paused_time = 0.0; + bool show_progress = params.background || tile_manager.get_num_effective_samples() != INT_MAX; + progress.set_total_pixel_samples(show_progress? tile_manager.state.total_pixel_samples : 0); if(!params.background) - progress.set_start_time(start_time); - progress.set_render_start_time(start_time); + progress.set_start_time(); + progress.set_render_start_time(); } void Session::reset(BufferParams& buffer_params, int samples) @@ -739,10 +824,10 @@ void Session::reset(BufferParams& buffer_params, int samples) if(params.progressive_refine) { thread_scoped_lock buffers_lock(buffers_mutex); - foreach(RenderBuffers *buffers, tile_buffers) - delete buffers; + foreach(RenderTile &rtile, render_tiles) + delete rtile.buffers; - tile_buffers.clear(); + render_tiles.clear(); } } @@ -821,6 +906,8 @@ void Session::update_scene() /* update scene */ if(scene->need_update()) { + load_kernels(false); + progress.set_status("Updating Scene"); MEM_GUARDED_CALL(&progress, scene->device_update, device, progress); } @@ -828,67 +915,51 @@ void Session::update_scene() void Session::update_status_time(bool show_pause, bool show_done) { - int sample = tile_manager.state.sample; - int resolution = tile_manager.state.resolution_divider; + int progressive_sample = tile_manager.state.sample; + int num_samples = tile_manager.get_num_effective_samples(); + + int tile = progress.get_rendered_tiles(); int num_tiles = tile_manager.state.num_tiles; - int tile = tile_manager.state.num_rendered_tiles; /* update status */ string status, substatus; if(!params.progressive) { - const int progress_sample = progress.get_sample(), - num_samples = tile_manager.get_num_effective_samples(); - const bool is_gpu = params.device.type == DEVICE_CUDA || params.device.type == DEVICE_OPENCL; - const bool is_multidevice = params.device.multi_devices.size() > 1; const bool is_cpu = params.device.type == DEVICE_CPU; - const bool is_last_tile = (num_samples * num_tiles - progress_sample) < num_samples; - - substatus = string_printf("Path Tracing Tile %d/%d", tile, num_tiles); - - if((is_gpu && !is_multidevice && !device->info.use_split_kernel) || - (is_cpu && (num_tiles == 1 || is_last_tile))) - { - /* When using split-kernel (OpenCL) each thread in a tile will be working on a different - * sample. Can't display sample number when device uses split-kernel + const bool rendering_finished = (tile == num_tiles); + const bool is_last_tile = (tile + 1) == num_tiles; + + substatus = string_printf("Rendered %d/%d Tiles", tile, num_tiles); + + if(!rendering_finished && (device->show_samples() || (is_cpu && is_last_tile))) { + /* Some devices automatically support showing the sample number: + * - CUDADevice + * - OpenCLDevice when using the megakernel (the split kernel renders multiple + * samples at the same time, so the current sample isn't really defined) + * - CPUDevice when using one thread + * For these devices, the current sample is always shown. + * + * The other option is when the last tile is currently being rendered by the CPU. */ - - /* when rendering on GPU multithreading happens within single tile, as in - * tiles are handling sequentially and in this case we could display - * currently rendering sample number - * this helps a lot from feedback point of view. - * also display the info on CPU, when using 1 tile only - */ - - int status_sample = progress_sample; - if(tile > 1) { - /* sample counter is global for all tiles, subtract samples - * from already finished tiles to get sample counter for - * current tile only - */ - if(is_cpu && is_last_tile && num_tiles > 1) { - status_sample = num_samples - (num_samples * num_tiles - progress_sample); - } - else { - status_sample -= (tile - 1) * num_samples; - } - } - - substatus += string_printf(", Sample %d/%d", status_sample, num_samples); + substatus += string_printf(", Sample %d/%d", progress.get_current_sample(), num_samples); + } + if(params.use_denoising) { + substatus += string_printf(", Denoised %d tiles", progress.get_denoised_tiles()); } } else if(tile_manager.num_samples == INT_MAX) - substatus = string_printf("Path Tracing Sample %d", sample+1); + substatus = string_printf("Path Tracing Sample %d", progressive_sample+1); else substatus = string_printf("Path Tracing Sample %d/%d", - sample+1, - tile_manager.get_num_effective_samples()); + progressive_sample+1, + num_samples); if(show_pause) { status = "Paused"; } else if(show_done) { status = "Done"; + progress.set_end_time(); /* Save end time so that further calls to get_time are accurate. */ } else { status = substatus; @@ -896,37 +967,41 @@ void Session::update_status_time(bool show_pause, bool show_done) } progress.set_status(status, substatus); - - /* update timing */ - if(preview_time == 0.0 && resolution == 1) - preview_time = time_dt(); - - double tile_time = (tile == 0 || sample == 0)? 0.0: (time_dt() - preview_time - paused_time) / sample; - - /* negative can happen when we pause a bit before rendering, can discard that */ - if(preview_time < 0.0) preview_time = 0.0; - - progress.set_tile(tile, tile_time); } -void Session::update_progress_sample() +void Session::render() { - progress.increment_sample(); -} + /* Clear buffers. */ + if(buffers && tile_manager.state.sample == 0) { + buffers->zero(device); + } -void Session::path_trace() -{ - /* add path trace task */ - DeviceTask task(DeviceTask::PATH_TRACE); + /* Add path trace task. */ + DeviceTask task(DeviceTask::RENDER); task.acquire_tile = function_bind(&Session::acquire_tile, this, _1, _2); task.release_tile = function_bind(&Session::release_tile, this, _1); + 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); task.update_tile_sample = function_bind(&Session::update_tile_sample, this, _1); - task.update_progress_sample = function_bind(&Session::update_progress_sample, this); + task.update_progress_sample = function_bind(&Progress::add_samples, &this->progress, _1, _2); task.need_finish_queue = params.progressive_refine; task.integrator_branched = scene->integrator->method == Integrator::BRANCHED_PATH; task.requested_tile_size = params.tile_size; + task.passes_size = tile_manager.params.get_passes_size(); + + if(params.use_denoising) { + task.denoising_radius = params.denoising_radius; + task.denoising_strength = params.denoising_strength; + task.denoising_feature_strength = params.denoising_feature_strength; + task.denoising_relative_pca = params.denoising_relative_pca; + + assert(!scene->film->need_update); + task.pass_stride = scene->film->pass_stride; + task.pass_denoising_data = scene->film->denoising_data_offset; + task.pass_denoising_clean = scene->film->denoising_clean_offset; + } device->task_add(task); } @@ -971,9 +1046,7 @@ bool Session::update_progressive_refine(bool cancel) } if(params.progressive_refine) { - foreach(RenderBuffers *buffers, tile_buffers) { - RenderTile rtile; - rtile.buffers = buffers; + foreach(RenderTile &rtile, render_tiles) { rtile.sample = sample; if(write) { @@ -982,7 +1055,7 @@ bool Session::update_progressive_refine(bool cancel) } else { if(update_render_tile_cb) - update_render_tile_cb(rtile); + update_render_tile_cb(rtile, true); } } } @@ -996,10 +1069,11 @@ void Session::device_free() { scene->device_free(); - foreach(RenderBuffers *buffers, tile_buffers) - delete buffers; + foreach(RenderTile &tile, render_tiles) + delete tile.buffers; + tile_manager.free_device(); - tile_buffers.clear(); + render_tiles.clear(); /* used from background render only, so no need to * re-create render/display buffers here |