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