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