Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles/render/session.cpp')
-rw-r--r--intern/cycles/render/session.cpp412
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