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