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