74cfd02e1a46359000884554e188911f2eb7b2e1
[blender.git] / intern / cycles / render / session.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <string.h>
18 #include <limits.h>
19
20 #include "render/buffers.h"
21 #include "render/camera.h"
22 #include "device/device.h"
23 #include "render/graph.h"
24 #include "render/integrator.h"
25 #include "render/mesh.h"
26 #include "render/object.h"
27 #include "render/scene.h"
28 #include "render/session.h"
29 #include "render/bake.h"
30
31 #include "util/util_foreach.h"
32 #include "util/util_function.h"
33 #include "util/util_logging.h"
34 #include "util/util_math.h"
35 #include "util/util_opengl.h"
36 #include "util/util_task.h"
37 #include "util/util_time.h"
38
39 CCL_NAMESPACE_BEGIN
40
41 /* Note about  preserve_tile_device option for tile manager:
42  * progressive refine and viewport rendering does requires tiles to
43  * always be allocated for the same device
44  */
45 Session::Session(const SessionParams& params_)
46 : params(params_),
47   tile_manager(params.progressive, params.samples, params.tile_size, params.start_resolution,
48        params.background == false || params.progressive_refine, params.background, params.tile_order,
49        max(params.device.multi_devices.size(), 1), params.pixel_size),
50   stats()
51 {
52         device_use_gl = ((params.device.type != DEVICE_CPU) && !params.background);
53
54         TaskScheduler::init(params.threads);
55
56         device = Device::create(params.device, stats, params.background);
57
58         if(params.background && params.output_path.empty()) {
59                 buffers = NULL;
60                 display = NULL;
61         }
62         else {
63                 buffers = new RenderBuffers(device);
64                 display = new DisplayBuffer(device, params.display_buffer_linear);
65         }
66
67         session_thread = NULL;
68         scene = NULL;
69
70         reset_time = 0.0;
71         last_update_time = 0.0;
72
73         delayed_reset.do_reset = false;
74         delayed_reset.samples = 0;
75
76         display_outdated = false;
77         gpu_draw_ready = false;
78         gpu_need_tonemap = false;
79         pause = false;
80         kernels_loaded = false;
81
82         /* TODO(sergey): Check if it's indeed optimal value for the split kernel. */
83         max_closure_global = 1;
84 }
85
86 Session::~Session()
87 {
88         if(session_thread) {
89                 /* wait for session thread to end */
90                 progress.set_cancel("Exiting");
91
92                 gpu_need_tonemap = false;
93                 gpu_need_tonemap_cond.notify_all();
94
95                 {
96                         thread_scoped_lock pause_lock(pause_mutex);
97                         pause = false;
98                 }
99                 pause_cond.notify_all();
100
101                 wait();
102         }
103
104         if(!params.output_path.empty()) {
105                 /* tonemap and write out image if requested */
106                 delete display;
107
108                 display = new DisplayBuffer(device, false);
109                 display->reset(buffers->params);
110                 tonemap(params.samples);
111
112                 progress.set_status("Writing Image", params.output_path);
113                 display->write(params.output_path);
114         }
115
116         /* clean up */
117         tile_manager.device_free();
118
119         delete buffers;
120         delete display;
121         delete scene;
122         delete device;
123
124         TaskScheduler::exit();
125 }
126
127 void Session::start()
128 {
129         session_thread = new thread(function_bind(&Session::run, this));
130 }
131
132 bool Session::ready_to_reset()
133 {
134         double dt = time_dt() - reset_time;
135
136         if(!display_outdated)
137                 return (dt > params.reset_timeout);
138         else
139                 return (dt > params.cancel_timeout);
140 }
141
142 /* GPU Session */
143
144 void Session::reset_gpu(BufferParams& buffer_params, int samples)
145 {
146         thread_scoped_lock pause_lock(pause_mutex);
147
148         /* block for buffer access and reset immediately. we can't do this
149          * in the thread, because we need to allocate an OpenGL buffer, and
150          * that only works in the main thread */
151         thread_scoped_lock display_lock(display_mutex);
152         thread_scoped_lock buffers_lock(buffers_mutex);
153
154         display_outdated = true;
155         reset_time = time_dt();
156
157         reset_(buffer_params, samples);
158
159         gpu_need_tonemap = false;
160         gpu_need_tonemap_cond.notify_all();
161
162         pause_cond.notify_all();
163 }
164
165 bool Session::draw_gpu(BufferParams& buffer_params, DeviceDrawParams& draw_params)
166 {
167         /* block for buffer access */
168         thread_scoped_lock display_lock(display_mutex);
169
170         /* first check we already rendered something */
171         if(gpu_draw_ready) {
172                 /* then verify the buffers have the expected size, so we don't
173                  * draw previous results in a resized window */
174                 if(!buffer_params.modified(display->params)) {
175                         /* for CUDA we need to do tonemapping still, since we can
176                          * only access GL buffers from the main thread */
177                         if(gpu_need_tonemap) {
178                                 thread_scoped_lock buffers_lock(buffers_mutex);
179                                 tonemap(tile_manager.state.sample);
180                                 gpu_need_tonemap = false;
181                                 gpu_need_tonemap_cond.notify_all();
182                         }
183
184                         display->draw(device, draw_params);
185
186                         if(display_outdated && (time_dt() - reset_time) > params.text_timeout)
187                                 return false;
188
189                         return true;
190                 }
191         }
192
193         return false;
194 }
195
196 void Session::run_gpu()
197 {
198         bool tiles_written = false;
199
200         reset_time = time_dt();
201         last_update_time = time_dt();
202
203         progress.set_render_start_time();
204
205         while(!progress.get_cancel()) {
206                 /* advance to next tile */
207                 bool no_tiles = !tile_manager.next();
208
209                 if(params.background) {
210                         /* if no work left and in background mode, we can stop immediately */
211                         if(no_tiles) {
212                                 progress.set_status("Finished");
213                                 break;
214                         }
215                 }
216                 else {
217                         /* if in interactive mode, and we are either paused or done for now,
218                          * wait for pause condition notify to wake up again */
219                         thread_scoped_lock pause_lock(pause_mutex);
220
221                         if(!pause && !tile_manager.done()) {
222                                 /* reset could have happened after no_tiles was set, before this lock.
223                                  * in this case we shall not wait for pause condition
224                                  */
225                         }
226                         else if(pause || no_tiles) {
227                                 update_status_time(pause, no_tiles);
228
229                                 while(1) {
230                                         scoped_timer pause_timer;
231                                         pause_cond.wait(pause_lock);
232                                         if(pause) {
233                                                 progress.add_skip_time(pause_timer, params.background);
234                                         }
235
236                                         update_status_time(pause, no_tiles);
237                                         progress.set_update();
238
239                                         if(!pause)
240                                                 break;
241                                 }
242                         }
243
244                         if(progress.get_cancel())
245                                 break;
246                 }
247
248                 if(!no_tiles) {
249                         /* update scene */
250                         scoped_timer update_timer;
251                         update_scene();
252                         progress.add_skip_time(update_timer, params.background);
253
254                         if(!device->error_message().empty())
255                                 progress.set_error(device->error_message());
256
257                         if(progress.get_cancel())
258                                 break;
259                 }
260
261                 if(!no_tiles) {
262                         /* buffers mutex is locked entirely while rendering each
263                          * sample, and released/reacquired on each iteration to allow
264                          * reset and draw in between */
265                         thread_scoped_lock buffers_lock(buffers_mutex);
266
267                         /* update status and timing */
268                         update_status_time();
269
270                         /* render */
271                         render();
272
273                         device->task_wait();
274
275                         if(!device->error_message().empty())
276                                 progress.set_cancel(device->error_message());
277
278                         /* update status and timing */
279                         update_status_time();
280
281                         gpu_need_tonemap = true;
282                         gpu_draw_ready = true;
283                         progress.set_update();
284
285                         /* wait for tonemap */
286                         if(!params.background) {
287                                 while(gpu_need_tonemap) {
288                                         if(progress.get_cancel())
289                                                 break;
290
291                                         gpu_need_tonemap_cond.wait(buffers_lock);
292                                 }
293                         }
294
295                         if(!device->error_message().empty())
296                                 progress.set_error(device->error_message());
297
298                         tiles_written = update_progressive_refine(progress.get_cancel());
299
300                         if(progress.get_cancel())
301                                 break;
302                 }
303         }
304
305         if(!tiles_written)
306                 update_progressive_refine(true);
307 }
308
309 /* CPU Session */
310
311 void Session::reset_cpu(BufferParams& buffer_params, int samples)
312 {
313         thread_scoped_lock reset_lock(delayed_reset.mutex);
314         thread_scoped_lock pause_lock(pause_mutex);
315
316         display_outdated = true;
317         reset_time = time_dt();
318
319         delayed_reset.params = buffer_params;
320         delayed_reset.samples = samples;
321         delayed_reset.do_reset = true;
322         device->task_cancel();
323
324         pause_cond.notify_all();
325 }
326
327 bool Session::draw_cpu(BufferParams& buffer_params, DeviceDrawParams& draw_params)
328 {
329         thread_scoped_lock display_lock(display_mutex);
330
331         /* first check we already rendered something */
332         if(display->draw_ready()) {
333                 /* then verify the buffers have the expected size, so we don't
334                  * draw previous results in a resized window */
335                 if(!buffer_params.modified(display->params)) {
336                         display->draw(device, draw_params);
337
338                         if(display_outdated && (time_dt() - reset_time) > params.text_timeout)
339                                 return false;
340
341                         return true;
342                 }
343         }
344
345         return false;
346 }
347
348 bool Session::acquire_tile(Device *tile_device, RenderTile& rtile)
349 {
350         if(progress.get_cancel()) {
351                 if(params.progressive_refine == false) {
352                         /* for progressive refine current sample should be finished for all tiles */
353                         return false;
354                 }
355         }
356
357         thread_scoped_lock tile_lock(tile_mutex);
358
359         /* get next tile from manager */
360         Tile *tile;
361         int device_num = device->device_number(tile_device);
362
363         if(!tile_manager.next_tile(tile, device_num))
364                 return false;
365         
366         /* fill render tile */
367         rtile.x = tile_manager.state.buffer.full_x + tile->x;
368         rtile.y = tile_manager.state.buffer.full_y + tile->y;
369         rtile.w = tile->w;
370         rtile.h = tile->h;
371         rtile.start_sample = tile_manager.state.sample;
372         rtile.num_samples = tile_manager.state.num_samples;
373         rtile.resolution = tile_manager.state.resolution_divider;
374         rtile.tile_index = tile->index;
375         rtile.task = (tile->state == Tile::DENOISE)? RenderTile::DENOISE: RenderTile::PATH_TRACE;
376
377         tile_lock.unlock();
378
379         /* in case of a permanent buffer, return it, otherwise we will allocate
380          * a new temporary buffer */
381         if(buffers) {
382                 tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride);
383
384                 rtile.buffer = buffers->buffer.device_pointer;
385                 rtile.buffers = buffers;
386
387                 device->map_tile(tile_device, rtile);
388
389                 return true;
390         }
391
392         if(tile->buffers == NULL) {
393                 /* fill buffer parameters */
394                 BufferParams buffer_params = tile_manager.params;
395                 buffer_params.full_x = rtile.x;
396                 buffer_params.full_y = rtile.y;
397                 buffer_params.width = rtile.w;
398                 buffer_params.height = rtile.h;
399
400                 /* allocate buffers */
401                 tile->buffers = new RenderBuffers(tile_device);
402                 tile->buffers->reset(buffer_params);
403         }
404
405         tile->buffers->params.get_offset_stride(rtile.offset, rtile.stride);
406
407         rtile.buffer = tile->buffers->buffer.device_pointer;
408         rtile.buffers = tile->buffers;
409         rtile.sample = tile_manager.state.sample;
410
411         /* this will tag tile as IN PROGRESS in blender-side render pipeline,
412          * which is needed to highlight currently rendering tile before first
413          * sample was processed for it
414          */
415         update_tile_sample(rtile);
416
417         return true;
418 }
419
420 void Session::update_tile_sample(RenderTile& rtile)
421 {
422         thread_scoped_lock tile_lock(tile_mutex);
423
424         if(update_render_tile_cb) {
425                 if(params.progressive_refine == false) {
426                         /* todo: optimize this by making it thread safe and removing lock */
427
428                         update_render_tile_cb(rtile, true);
429                 }
430         }
431
432         update_status_time();
433 }
434
435 void Session::release_tile(RenderTile& rtile)
436 {
437         thread_scoped_lock tile_lock(tile_mutex);
438
439         progress.add_finished_tile(rtile.task == RenderTile::DENOISE);
440
441         bool delete_tile;
442
443         if(tile_manager.finish_tile(rtile.tile_index, delete_tile)) {
444                 if(write_render_tile_cb && params.progressive_refine == false) {
445                         write_render_tile_cb(rtile);
446                 }
447
448                 if(delete_tile) {
449                         delete rtile.buffers;
450                         tile_manager.state.tiles[rtile.tile_index].buffers = NULL;
451                 }
452         }
453         else {
454                 if(update_render_tile_cb && params.progressive_refine == false) {
455                         update_render_tile_cb(rtile, false);
456                 }
457         }
458
459         update_status_time();
460 }
461
462 void Session::map_neighbor_tiles(RenderTile *tiles, Device *tile_device)
463 {
464         thread_scoped_lock tile_lock(tile_mutex);
465
466         int center_idx = tiles[4].tile_index;
467         assert(tile_manager.state.tiles[center_idx].state == Tile::DENOISE);
468         BufferParams buffer_params = tile_manager.params;
469         int4 image_region = make_int4(buffer_params.full_x, buffer_params.full_y,
470                                       buffer_params.full_x + buffer_params.width, buffer_params.full_y + buffer_params.height);
471
472         for(int dy = -1, i = 0; dy <= 1; dy++) {
473                 for(int dx = -1; dx <= 1; dx++, i++) {
474                         int px = tiles[4].x + dx*params.tile_size.x;
475                         int py = tiles[4].y + dy*params.tile_size.y;
476                         if(px >= image_region.x && py >= image_region.y &&
477                            px <  image_region.z && py <  image_region.w) {
478                                 int tile_index = center_idx + dy*tile_manager.state.tile_stride + dx;
479                                 Tile *tile = &tile_manager.state.tiles[tile_index];
480                                 assert(tile->buffers);
481
482                                 tiles[i].buffer = tile->buffers->buffer.device_pointer;
483                                 tiles[i].x = tile_manager.state.buffer.full_x + tile->x;
484                                 tiles[i].y = tile_manager.state.buffer.full_y + tile->y;
485                                 tiles[i].w = tile->w;
486                                 tiles[i].h = tile->h;
487                                 tiles[i].buffers = tile->buffers;
488
489                                 tile->buffers->params.get_offset_stride(tiles[i].offset, tiles[i].stride);
490                         }
491                         else {
492                                 tiles[i].buffer = (device_ptr)NULL;
493                                 tiles[i].buffers = NULL;
494                                 tiles[i].x = clamp(px, image_region.x, image_region.z);
495                                 tiles[i].y = clamp(py, image_region.y, image_region.w);
496                                 tiles[i].w = tiles[i].h = 0;
497                         }
498                 }
499         }
500
501         assert(tiles[4].buffers);
502         device->map_neighbor_tiles(tile_device, tiles);
503 }
504
505 void Session::unmap_neighbor_tiles(RenderTile *tiles, Device *tile_device)
506 {
507         thread_scoped_lock tile_lock(tile_mutex);
508         device->unmap_neighbor_tiles(tile_device, tiles);
509 }
510
511 void Session::run_cpu()
512 {
513         bool tiles_written = false;
514
515         last_update_time = time_dt();
516
517         {
518                 /* reset once to start */
519                 thread_scoped_lock reset_lock(delayed_reset.mutex);
520                 thread_scoped_lock buffers_lock(buffers_mutex);
521                 thread_scoped_lock display_lock(display_mutex);
522
523                 reset_(delayed_reset.params, delayed_reset.samples);
524                 delayed_reset.do_reset = false;
525         }
526
527         while(!progress.get_cancel()) {
528                 /* advance to next tile */
529                 bool no_tiles = !tile_manager.next();
530                 bool need_tonemap = false;
531
532                 if(params.background) {
533                         /* if no work left and in background mode, we can stop immediately */
534                         if(no_tiles) {
535                                 progress.set_status("Finished");
536                                 break;
537                         }
538                 }
539                 else {
540                         /* if in interactive mode, and we are either paused or done for now,
541                          * wait for pause condition notify to wake up again */
542                         thread_scoped_lock pause_lock(pause_mutex);
543
544                         if(!pause && delayed_reset.do_reset) {
545                                 /* reset once to start */
546                                 thread_scoped_lock reset_lock(delayed_reset.mutex);
547                                 thread_scoped_lock buffers_lock(buffers_mutex);
548                                 thread_scoped_lock display_lock(display_mutex);
549
550                                 reset_(delayed_reset.params, delayed_reset.samples);
551                                 delayed_reset.do_reset = false;
552                         }
553                         else if(pause || no_tiles) {
554                                 update_status_time(pause, no_tiles);
555
556                                 while(1) {
557                                         scoped_timer pause_timer;
558                                         pause_cond.wait(pause_lock);
559                                         if(pause) {
560                                                 progress.add_skip_time(pause_timer, params.background);
561                                         }
562
563                                         update_status_time(pause, no_tiles);
564                                         progress.set_update();
565
566                                         if(!pause)
567                                                 break;
568                                 }
569                         }
570
571                         if(progress.get_cancel())
572                                 break;
573                 }
574
575                 if(!no_tiles) {
576                         /* buffers mutex is locked entirely while rendering each
577                          * sample, and released/reacquired on each iteration to allow
578                          * reset and draw in between */
579                         thread_scoped_lock buffers_lock(buffers_mutex);
580
581                         /* update scene */
582                         scoped_timer update_timer;
583                         update_scene();
584                         progress.add_skip_time(update_timer, params.background);
585
586                         if(!device->error_message().empty())
587                                 progress.set_error(device->error_message());
588
589                         if(progress.get_cancel())
590                                 break;
591
592                         /* update status and timing */
593                         update_status_time();
594
595                         /* render */
596                         render();
597
598                         /* update status and timing */
599                         update_status_time();
600
601                         if(!params.background)
602                                 need_tonemap = true;
603
604                         if(!device->error_message().empty())
605                                 progress.set_error(device->error_message());
606                 }
607
608                 device->task_wait();
609
610                 {
611                         thread_scoped_lock reset_lock(delayed_reset.mutex);
612                         thread_scoped_lock buffers_lock(buffers_mutex);
613                         thread_scoped_lock display_lock(display_mutex);
614
615                         if(delayed_reset.do_reset) {
616                                 /* reset rendering if request from main thread */
617                                 delayed_reset.do_reset = false;
618                                 reset_(delayed_reset.params, delayed_reset.samples);
619                         }
620                         else if(need_tonemap) {
621                                 /* tonemap only if we do not reset, we don't we don't
622                                  * want to show the result of an incomplete sample */
623                                 tonemap(tile_manager.state.sample);
624                         }
625
626                         if(!device->error_message().empty())
627                                 progress.set_error(device->error_message());
628
629                         tiles_written = update_progressive_refine(progress.get_cancel());
630                 }
631
632                 progress.set_update();
633         }
634
635         if(!tiles_written)
636                 update_progressive_refine(true);
637 }
638
639 DeviceRequestedFeatures Session::get_requested_device_features()
640 {
641         /* TODO(sergey): Consider moving this to the Scene level. */
642         DeviceRequestedFeatures requested_features;
643         requested_features.experimental = params.experimental;
644
645         requested_features.max_closure = get_max_closure_count();
646         scene->shader_manager->get_requested_features(
647                 scene,
648                 &requested_features);
649         if(!params.background) {
650                 /* Avoid too much re-compilations for viewport render. */
651                 requested_features.max_closure = 64;
652                 requested_features.max_nodes_group = NODE_GROUP_LEVEL_MAX;
653                 requested_features.nodes_features = NODE_FEATURE_ALL;
654         }
655
656         /* This features are not being tweaked as often as shaders,
657          * so could be done selective magic for the viewport as well.
658          */
659         requested_features.use_hair = false;
660         requested_features.use_object_motion = false;
661         requested_features.use_camera_motion = scene->camera->use_motion;
662         foreach(Object *object, scene->objects) {
663                 Mesh *mesh = object->mesh;
664                 if(mesh->num_curves()) {
665                         requested_features.use_hair = true;
666                 }
667                 requested_features.use_object_motion |= object->use_motion | mesh->use_motion_blur;
668                 requested_features.use_camera_motion |= mesh->use_motion_blur;
669 #ifdef WITH_OPENSUBDIV
670                 if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE) {
671                         requested_features.use_patch_evaluation = true;
672                 }
673 #endif
674                 if(object->is_shadow_catcher) {
675                         requested_features.use_shadow_tricks = true;
676                 }
677         }
678
679         BakeManager *bake_manager = scene->bake_manager;
680         requested_features.use_baking = bake_manager->get_baking();
681         requested_features.use_integrator_branched = (scene->integrator->method == Integrator::BRANCHED_PATH);
682         requested_features.use_denoising = params.use_denoising;
683
684         return requested_features;
685 }
686
687 void Session::load_kernels(bool lock_scene)
688 {
689         thread_scoped_lock scene_lock;
690         if(lock_scene) {
691                 scene_lock = thread_scoped_lock(scene->mutex);
692         }
693
694         DeviceRequestedFeatures requested_features = get_requested_device_features();
695
696         if(!kernels_loaded || loaded_kernel_features.modified(requested_features)) {
697                 progress.set_status("Loading render kernels (may take a few minutes the first time)");
698
699                 scoped_timer timer;
700
701                 VLOG(2) << "Requested features:\n" << requested_features;
702                 if(!device->load_kernels(requested_features)) {
703                         string message = device->error_message();
704                         if(message.empty())
705                                 message = "Failed loading render kernel, see console for errors";
706
707                         progress.set_error(message);
708                         progress.set_status("Error", message);
709                         progress.set_update();
710                         return;
711                 }
712
713                 progress.add_skip_time(timer, false);
714                 VLOG(1) << "Total time spent loading kernels: " << time_dt() - timer.get_start();
715
716                 kernels_loaded = true;
717                 loaded_kernel_features = requested_features;
718         }
719 }
720
721 void Session::run()
722 {
723         /* load kernels */
724         load_kernels();
725
726         /* session thread loop */
727         progress.set_status("Waiting for render to start");
728
729         /* run */
730         if(!progress.get_cancel()) {
731                 /* reset number of rendered samples */
732                 progress.reset_sample();
733
734                 if(device_use_gl)
735                         run_gpu();
736                 else
737                         run_cpu();
738         }
739
740         /* progress update */
741         if(progress.get_cancel())
742                 progress.set_status("Cancel", progress.get_cancel_message());
743         else
744                 progress.set_update();
745 }
746
747 bool Session::draw(BufferParams& buffer_params, DeviceDrawParams &draw_params)
748 {
749         if(device_use_gl)
750                 return draw_gpu(buffer_params, draw_params);
751         else
752                 return draw_cpu(buffer_params, draw_params);
753 }
754
755 void Session::reset_(BufferParams& buffer_params, int samples)
756 {
757         if(buffers && buffer_params.modified(tile_manager.params)) {
758                 gpu_draw_ready = false;
759                 buffers->reset(buffer_params);
760                 if(display) {
761                         display->reset(buffer_params);
762                 }
763         }
764
765         tile_manager.reset(buffer_params, samples);
766         progress.reset_sample();
767
768         bool show_progress = params.background || tile_manager.get_num_effective_samples() != INT_MAX;
769         progress.set_total_pixel_samples(show_progress? tile_manager.state.total_pixel_samples : 0);
770
771         if(!params.background)
772                 progress.set_start_time();
773         progress.set_render_start_time();
774 }
775
776 void Session::reset(BufferParams& buffer_params, int samples)
777 {
778         if(device_use_gl)
779                 reset_gpu(buffer_params, samples);
780         else
781                 reset_cpu(buffer_params, samples);
782 }
783
784 void Session::set_samples(int samples)
785 {
786         if(samples != params.samples) {
787                 params.samples = samples;
788                 tile_manager.set_samples(samples);
789
790                 {
791                         thread_scoped_lock pause_lock(pause_mutex);
792                 }
793                 pause_cond.notify_all();
794         }
795 }
796
797 void Session::set_pause(bool pause_)
798 {
799         bool notify = false;
800
801         {
802                 thread_scoped_lock pause_lock(pause_mutex);
803
804                 if(pause != pause_) {
805                         pause = pause_;
806                         notify = true;
807                 }
808         }
809
810         if(notify)
811                 pause_cond.notify_all();
812 }
813
814 void Session::wait()
815 {
816         session_thread->join();
817         delete session_thread;
818
819         session_thread = NULL;
820 }
821
822 void Session::update_scene()
823 {
824         thread_scoped_lock scene_lock(scene->mutex);
825
826         /* update camera if dimensions changed for progressive render. the camera
827          * knows nothing about progressive or cropped rendering, it just gets the
828          * image dimensions passed in */
829         Camera *cam = scene->camera;
830         int width = tile_manager.state.buffer.full_width;
831         int height = tile_manager.state.buffer.full_height;
832         int resolution = tile_manager.state.resolution_divider;
833
834         if(width != cam->width || height != cam->height) {
835                 cam->width = width;
836                 cam->height = height;
837                 cam->resolution = resolution;
838                 cam->tag_update();
839         }
840
841         /* number of samples is needed by multi jittered
842          * sampling pattern and by baking */
843         Integrator *integrator = scene->integrator;
844         BakeManager *bake_manager = scene->bake_manager;
845
846         if(integrator->sampling_pattern == SAMPLING_PATTERN_CMJ ||
847            bake_manager->get_baking())
848         {
849                 int aa_samples = tile_manager.num_samples;
850
851                 if(aa_samples != integrator->aa_samples) {
852                         integrator->aa_samples = aa_samples;
853                         integrator->tag_update(scene);
854                 }
855         }
856
857         /* update scene */
858         if(scene->need_update()) {
859                 load_kernels(false);
860
861                 progress.set_status("Updating Scene");
862                 MEM_GUARDED_CALL(&progress, scene->device_update, device, progress);
863         }
864 }
865
866 void Session::update_status_time(bool show_pause, bool show_done)
867 {
868         int progressive_sample = tile_manager.state.sample;
869         int num_samples = tile_manager.get_num_effective_samples();
870
871         int tile = progress.get_rendered_tiles();
872         int num_tiles = tile_manager.state.num_tiles;
873
874         /* update status */
875         string status, substatus;
876
877         if(!params.progressive) {
878                 const bool is_cpu = params.device.type == DEVICE_CPU;
879                 const bool rendering_finished = (tile == num_tiles);
880                 const bool is_last_tile = (tile + 1) == num_tiles;
881
882                 substatus = string_printf("Rendered %d/%d Tiles", tile, num_tiles);
883
884                 if(!rendering_finished && (device->show_samples() || (is_cpu && is_last_tile))) {
885                         /* Some devices automatically support showing the sample number:
886                          * - CUDADevice
887                          * - OpenCLDevice when using the megakernel (the split kernel renders multiple
888                          *   samples at the same time, so the current sample isn't really defined)
889                          * - CPUDevice when using one thread
890                          * For these devices, the current sample is always shown.
891                          *
892                          * The other option is when the last tile is currently being rendered by the CPU.
893                          */
894                         substatus += string_printf(", Sample %d/%d", progress.get_current_sample(), num_samples);
895                 }
896                 if(params.use_denoising) {
897                         substatus += string_printf(", Denoised %d tiles", progress.get_denoised_tiles());
898                 }
899         }
900         else if(tile_manager.num_samples == INT_MAX)
901                 substatus = string_printf("Path Tracing Sample %d", progressive_sample+1);
902         else
903                 substatus = string_printf("Path Tracing Sample %d/%d",
904                                           progressive_sample+1,
905                                           num_samples);
906         
907         if(show_pause) {
908                 status = "Paused";
909         }
910         else if(show_done) {
911                 status = "Done";
912                 progress.set_end_time(); /* Save end time so that further calls to get_time are accurate. */
913         }
914         else {
915                 status = substatus;
916                 substatus.clear();
917         }
918
919         progress.set_status(status, substatus);
920 }
921
922 void Session::render()
923 {
924         /* Clear buffers. */
925         if(buffers && tile_manager.state.sample == tile_manager.range_start_sample) {
926                 buffers->zero();
927         }
928
929         /* Add path trace task. */
930         DeviceTask task(DeviceTask::RENDER);
931         
932         task.acquire_tile = function_bind(&Session::acquire_tile, this, _1, _2);
933         task.release_tile = function_bind(&Session::release_tile, this, _1);
934         task.map_neighbor_tiles = function_bind(&Session::map_neighbor_tiles, this, _1, _2);
935         task.unmap_neighbor_tiles = function_bind(&Session::unmap_neighbor_tiles, this, _1, _2);
936         task.get_cancel = function_bind(&Progress::get_cancel, &this->progress);
937         task.update_tile_sample = function_bind(&Session::update_tile_sample, this, _1);
938         task.update_progress_sample = function_bind(&Progress::add_samples, &this->progress, _1, _2);
939         task.need_finish_queue = params.progressive_refine;
940         task.integrator_branched = scene->integrator->method == Integrator::BRANCHED_PATH;
941         task.requested_tile_size = params.tile_size;
942         task.passes_size = tile_manager.params.get_passes_size();
943
944         if(params.use_denoising) {
945                 task.denoising_radius = params.denoising_radius;
946                 task.denoising_strength = params.denoising_strength;
947                 task.denoising_feature_strength = params.denoising_feature_strength;
948                 task.denoising_relative_pca = params.denoising_relative_pca;
949
950                 assert(!scene->film->need_update);
951                 task.pass_stride = scene->film->pass_stride;
952                 task.pass_denoising_data = scene->film->denoising_data_offset;
953                 task.pass_denoising_clean = scene->film->denoising_clean_offset;
954         }
955
956         device->task_add(task);
957 }
958
959 void Session::tonemap(int sample)
960 {
961         /* add tonemap task */
962         DeviceTask task(DeviceTask::FILM_CONVERT);
963
964         task.x = tile_manager.state.buffer.full_x;
965         task.y = tile_manager.state.buffer.full_y;
966         task.w = tile_manager.state.buffer.width;
967         task.h = tile_manager.state.buffer.height;
968         task.rgba_byte = display->rgba_byte.device_pointer;
969         task.rgba_half = display->rgba_half.device_pointer;
970         task.buffer = buffers->buffer.device_pointer;
971         task.sample = sample;
972         tile_manager.state.buffer.get_offset_stride(task.offset, task.stride);
973
974         if(task.w > 0 && task.h > 0) {
975                 device->task_add(task);
976                 device->task_wait();
977
978                 /* set display to new size */
979                 display->draw_set(task.w, task.h);
980         }
981
982         display_outdated = false;
983 }
984
985 bool Session::update_progressive_refine(bool cancel)
986 {
987         int sample = tile_manager.state.sample + 1;
988         bool write = sample == tile_manager.num_samples || cancel;
989
990         double current_time = time_dt();
991
992         if(current_time - last_update_time < params.progressive_update_timeout) {
993                 /* if last sample was processed, we need to write buffers anyway  */
994                 if(!write && sample != 1)
995                         return false;
996         }
997
998         if(params.progressive_refine) {
999                 foreach(Tile& tile, tile_manager.state.tiles) {
1000                         if(!tile.buffers) {
1001                                 continue;
1002                         }
1003
1004                         RenderTile rtile;
1005                         rtile.x = tile_manager.state.buffer.full_x + tile.x;
1006                         rtile.y = tile_manager.state.buffer.full_y + tile.y;
1007                         rtile.w = tile.w;
1008                         rtile.h = tile.h;
1009                         rtile.sample = sample;
1010                         rtile.buffers = tile.buffers;
1011
1012                         if(write) {
1013                                 if(write_render_tile_cb)
1014                                         write_render_tile_cb(rtile);
1015                         }
1016                         else {
1017                                 if(update_render_tile_cb)
1018                                         update_render_tile_cb(rtile, true);
1019                         }
1020                 }
1021         }
1022
1023         last_update_time = current_time;
1024
1025         return write;
1026 }
1027
1028 void Session::device_free()
1029 {
1030         scene->device_free();
1031
1032         tile_manager.device_free();
1033
1034         /* used from background render only, so no need to
1035          * re-create render/display buffers here
1036          */
1037 }
1038
1039 int Session::get_max_closure_count()
1040 {
1041         int max_closures = 0;
1042         for(int i = 0; i < scene->shaders.size(); i++) {
1043                 int num_closures = scene->shaders[i]->graph->get_num_closures();
1044                 max_closures = max(max_closures, num_closures);
1045         }
1046         max_closure_global = max(max_closure_global, max_closures);
1047         return max_closure_global;
1048 }
1049
1050 CCL_NAMESPACE_END