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