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