diff options
Diffstat (limited to 'intern/cycles/render/session.cpp')
-rw-r--r-- | intern/cycles/render/session.cpp | 162 |
1 files changed, 125 insertions, 37 deletions
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index c22e29043d3..a60542259f6 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -61,22 +61,6 @@ Session::Session(const SessionParams ¶ms_) TaskScheduler::init(params.threads); - /* Create CPU/GPU devices. */ - device = Device::create(params.device, stats, profiler, params.background); - - /* Create buffers for interactive rendering. */ - if (params.background && !params.write_render_cb) { - buffers = NULL; - display = NULL; - } - else { - buffers = new RenderBuffers(device); - display = new DisplayBuffer(device, params.display_buffer_linear); - } - - /* Validate denoising parameters. */ - set_denoising(params.denoising); - session_thread = NULL; scene = NULL; @@ -90,6 +74,26 @@ Session::Session(const SessionParams ¶ms_) gpu_draw_ready = false; gpu_need_display_buffer_update = false; pause = false; + + buffers = NULL; + display = NULL; + + /* Validate denoising parameters. */ + set_denoising(params.denoising); + + /* Create CPU/GPU devices. */ + device = Device::create(params.device, stats, profiler, params.background); + + if (!device->error_message().empty()) { + progress.set_error(device->error_message()); + return; + } + + /* Create buffers for interactive rendering. */ + if (!(params.background && !params.write_render_cb)) { + buffers = new RenderBuffers(device); + display = new DisplayBuffer(device, params.display_buffer_linear); + } } Session::~Session() @@ -110,7 +114,7 @@ Session::~Session() wait(); } - if (params.write_render_cb) { + if (buffers && params.write_render_cb) { /* Copy to display buffer and write out image if requested */ delete display; @@ -378,6 +382,62 @@ bool Session::draw_cpu(BufferParams &buffer_params, DeviceDrawParams &draw_param return false; } +bool Session::steal_tile(RenderTile &rtile, Device *tile_device, thread_scoped_lock &tile_lock) +{ + /* Devices that can get their tiles stolen don't steal tiles themselves. + * Additionally, if there are no stealable tiles in flight, give up here. */ + if (tile_device->info.type == DEVICE_CPU || stealable_tiles == 0) { + return false; + } + + /* Wait until no other thread is trying to steal a tile. */ + while (tile_stealing_state != NOT_STEALING && stealable_tiles > 0) { + /* Someone else is currently trying to get a tile. + * Wait on the condition variable and try later. */ + tile_steal_cond.wait(tile_lock); + } + /* If another thread stole the last stealable tile in the meantime, give up. */ + if (stealable_tiles == 0) { + return false; + } + + /* There are stealable tiles in flight, so signal that one should be released. */ + tile_stealing_state = WAITING_FOR_TILE; + + /* Wait until a device notices the signal and releases its tile. */ + while (tile_stealing_state != GOT_TILE && stealable_tiles > 0) { + tile_steal_cond.wait(tile_lock); + } + /* If the last stealable tile finished on its own, give up. */ + if (tile_stealing_state != GOT_TILE) { + tile_stealing_state = NOT_STEALING; + return false; + } + + /* Successfully stole a tile, now move it to the new device. */ + rtile = stolen_tile; + rtile.buffers->buffer.move_device(tile_device); + rtile.buffer = rtile.buffers->buffer.device_pointer; + rtile.stealing_state = RenderTile::NO_STEALING; + rtile.num_samples -= (rtile.sample - rtile.start_sample); + rtile.start_sample = rtile.sample; + + tile_stealing_state = NOT_STEALING; + + /* Poke any threads which might be waiting for NOT_STEALING above. */ + tile_steal_cond.notify_one(); + + return true; +} + +bool Session::get_tile_stolen() +{ + /* If tile_stealing_state is WAITING_FOR_TILE, atomically set it to RELEASING_TILE + * and return true. */ + TileStealingState expected = WAITING_FOR_TILE; + return tile_stealing_state.compare_exchange_weak(expected, RELEASING_TILE); +} + bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_types) { if (progress.get_cancel()) { @@ -399,7 +459,8 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ denoising_cond.wait(tile_lock); continue; } - return false; + + return steal_tile(rtile, tile_device, tile_lock); } /* fill render tile */ @@ -415,11 +476,18 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ if (tile->state == Tile::DENOISE) { rtile.task = RenderTile::DENOISE; } - else if (read_bake_tile_cb) { - rtile.task = RenderTile::BAKE; - } else { - rtile.task = RenderTile::PATH_TRACE; + if (tile_device->info.type == DEVICE_CPU) { + stealable_tiles++; + rtile.stealing_state = RenderTile::CAN_BE_STOLEN; + } + + if (read_bake_tile_cb) { + rtile.task = RenderTile::BAKE; + } + else { + rtile.task = RenderTile::PATH_TRACE; + } } tile_lock.unlock(); @@ -504,6 +572,26 @@ void Session::release_tile(RenderTile &rtile, const bool need_denoise) { thread_scoped_lock tile_lock(tile_mutex); + if (rtile.stealing_state != RenderTile::NO_STEALING) { + stealable_tiles--; + if (rtile.stealing_state == RenderTile::WAS_STOLEN) { + /* If the tile is being stolen, don't release it here - the new device will pick up where + * the old one left off. */ + + assert(tile_stealing_state == RELEASING_TILE); + assert(rtile.sample < rtile.start_sample + rtile.num_samples); + + tile_stealing_state = GOT_TILE; + stolen_tile = rtile; + tile_steal_cond.notify_all(); + return; + } + else if (stealable_tiles == 0) { + /* If this was the last stealable tile, wake up any threads still waiting for one. */ + tile_steal_cond.notify_all(); + } + } + progress.add_finished_tile(rtile.task == RenderTile::DENOISE); bool delete_tile; @@ -811,6 +899,8 @@ void Session::reset_(BufferParams &buffer_params, int samples) } tile_manager.reset(buffer_params, samples); + stealable_tiles = 0; + tile_stealing_state = NOT_STEALING; progress.reset_sample(); bool show_progress = params.background || tile_manager.get_num_effective_samples() != INT_MAX; @@ -918,23 +1008,19 @@ bool Session::update_scene() int height = tile_manager.state.buffer.full_height; int resolution = tile_manager.state.resolution_divider; - if (width != cam->width || height != cam->height || resolution != cam->resolution) { - cam->width = width; - cam->height = height; - cam->resolution = resolution; - cam->tag_update(); - } + cam->set_screen_size_and_resolution(width, height, resolution); /* number of samples is needed by multi jittered * sampling pattern and by baking */ Integrator *integrator = scene->integrator; BakeManager *bake_manager = scene->bake_manager; - if (integrator->sampling_pattern != SAMPLING_PATTERN_SOBOL || bake_manager->get_baking()) { + if (integrator->get_sampling_pattern() != SAMPLING_PATTERN_SOBOL || bake_manager->get_baking()) { int aa_samples = tile_manager.num_samples; - if (aa_samples != integrator->aa_samples) { - integrator->aa_samples = aa_samples; + integrator->set_aa_samples(aa_samples); + + if (integrator->is_modified()) { integrator->tag_update(scene); } } @@ -1028,7 +1114,7 @@ bool Session::render_need_denoise(bool &delayed) /* 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) { + if (scene->film->is_modified() || !scene->film->get_denoising_data_offset()) { return false; } @@ -1071,10 +1157,12 @@ void Session::render(bool need_denoise) 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(&Progress::add_samples, &this->progress, _1, _2); + task.get_tile_stolen = function_bind(&Session::get_tile_stolen, this); task.need_finish_queue = params.progressive_refine; - task.integrator_branched = scene->integrator->method == Integrator::BRANCHED_PATH; + task.integrator_branched = scene->integrator->get_method() == Integrator::BRANCHED_PATH; - task.adaptive_sampling.use = (scene->integrator->sampling_pattern == SAMPLING_PATTERN_PMJ) && + task.adaptive_sampling.use = (scene->integrator->get_sampling_pattern() == + SAMPLING_PATTERN_PMJ) && scene->dscene.data.film.pass_adaptive_aux_buffer; task.adaptive_sampling.min_samples = scene->dscene.data.integrator.adaptive_min_samples; task.adaptive_sampling.adaptive_step = scene->dscene.data.integrator.adaptive_step; @@ -1085,10 +1173,10 @@ void Session::render(bool need_denoise) if (need_denoise) { task.denoising = params.denoising; - task.pass_stride = scene->film->pass_stride; + task.pass_stride = scene->film->get_pass_stride(); task.target_pass_stride = task.pass_stride; - task.pass_denoising_data = scene->film->denoising_data_offset; - task.pass_denoising_clean = scene->film->denoising_clean_offset; + task.pass_denoising_data = scene->film->get_denoising_data_offset(); + task.pass_denoising_clean = scene->film->get_denoising_clean_offset(); task.denoising_from_render = true; |