7303cb52ad82b4e95b4535fc8011213316e3470b
[blender.git] / intern / cycles / render / session.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include <string.h>
20 #include <limits.h>
21
22 #include "buffers.h"
23 #include "camera.h"
24 #include "device.h"
25 #include "scene.h"
26 #include "session.h"
27
28 #include "util_foreach.h"
29 #include "util_function.h"
30 #include "util_math.h"
31 #include "util_opengl.h"
32 #include "util_task.h"
33 #include "util_time.h"
34
35 CCL_NAMESPACE_BEGIN
36
37 /* Note about  preserve_tile_device option for tile manager:
38  * progressive refine and viewport rendering does requires tiles to
39  * always be allocated for the same device
40  */
41 Session::Session(const SessionParams& params_)
42 : params(params_),
43   tile_manager(params.progressive, params.samples, params.tile_size, params.start_resolution,
44        params.background == false || params.progressive_refine, params.background,
45        max(params.device.multi_devices.size(), 1)),
46   stats()
47 {
48         device_use_gl = ((params.device.type != DEVICE_CPU) && !params.background);
49
50         TaskScheduler::init(params.threads);
51
52         device = Device::create(params.device, stats, params.background, params.threads);
53
54         if(params.background) {
55                 buffers = NULL;
56                 display = NULL;
57         }
58         else {
59                 buffers = new RenderBuffers(device);
60                 display = new DisplayBuffer(device);
61         }
62
63         session_thread = NULL;
64         scene = NULL;
65
66         start_time = 0.0;
67         reset_time = 0.0;
68         preview_time = 0.0;
69         paused_time = 0.0;
70
71         delayed_reset.do_reset = false;
72         delayed_reset.samples = 0;
73
74         display_outdated = false;
75         gpu_draw_ready = false;
76         gpu_need_tonemap = false;
77         pause = false;
78         kernels_loaded = false;
79 }
80
81 Session::~Session()
82 {
83         if(session_thread) {
84                 progress.set_cancel("Exiting");
85
86                 gpu_need_tonemap = false;
87                 gpu_need_tonemap_cond.notify_all();
88
89                 {
90                         thread_scoped_lock pause_lock(pause_mutex);
91                         pause = false;
92                 }
93                 pause_cond.notify_all();
94
95                 wait();
96         }
97
98         if(display && params.output_path != "") {
99                 tonemap();
100
101                 progress.set_status("Writing Image", params.output_path);
102                 display->write(device, params.output_path);
103         }
104
105         foreach(RenderBuffers *buffers, tile_buffers)
106                 delete buffers;
107
108         delete buffers;
109         delete display;
110         delete scene;
111         delete device;
112
113         TaskScheduler::exit();
114 }
115
116 void Session::start()
117 {
118         session_thread = new thread(function_bind(&Session::run, this));
119 }
120
121 bool Session::ready_to_reset()
122 {
123         double dt = time_dt() - reset_time;
124
125         if(!display_outdated)
126                 return (dt > params.reset_timeout);
127         else
128                 return (dt > params.cancel_timeout);
129 }
130
131 /* GPU Session */
132
133 void Session::reset_gpu(BufferParams& buffer_params, int samples)
134 {
135         /* block for buffer acces and reset immediately. we can't do this
136          * in the thread, because we need to allocate an OpenGL buffer, and
137          * that only works in the main thread */
138         thread_scoped_lock display_lock(display_mutex);
139         thread_scoped_lock buffers_lock(buffers_mutex);
140
141         display_outdated = true;
142         reset_time = time_dt();
143
144         reset_(buffer_params, samples);
145
146         gpu_need_tonemap = false;
147         gpu_need_tonemap_cond.notify_all();
148
149         pause_cond.notify_all();
150 }
151
152 bool Session::draw_gpu(BufferParams& buffer_params)
153 {
154         /* block for buffer access */
155         thread_scoped_lock display_lock(display_mutex);
156
157         /* first check we already rendered something */
158         if(gpu_draw_ready) {
159                 /* then verify the buffers have the expected size, so we don't
160                  * draw previous results in a resized window */
161                 if(!buffer_params.modified(display->params)) {
162                         /* for CUDA we need to do tonemapping still, since we can
163                          * only access GL buffers from the main thread */
164                         if(gpu_need_tonemap) {
165                                 thread_scoped_lock buffers_lock(buffers_mutex);
166                                 tonemap();
167                                 gpu_need_tonemap = false;
168                                 gpu_need_tonemap_cond.notify_all();
169                         }
170
171                         display->draw(device);
172
173                         if(display_outdated && (time_dt() - reset_time) > params.text_timeout)
174                                 return false;
175
176                         return true;
177                 }
178         }
179
180         return false;
181 }
182
183 void Session::run_gpu()
184 {
185         bool tiles_written = false;
186
187         start_time = time_dt();
188         reset_time = time_dt();
189         paused_time = 0.0;
190         last_update_time = time_dt();
191
192         if(!params.background)
193                 progress.set_start_time(start_time + paused_time);
194
195         while(!progress.get_cancel()) {
196                 /* advance to next tile */
197                 bool no_tiles = !tile_manager.next();
198
199                 if(params.background) {
200                         /* if no work left and in background mode, we can stop immediately */
201                         if(no_tiles) {
202                                 progress.set_status("Finished");
203                                 break;
204                         }
205                 }
206                 else {
207                         /* if in interactive mode, and we are either paused or done for now,
208                          * wait for pause condition notify to wake up again */
209                         thread_scoped_lock pause_lock(pause_mutex);
210
211                         if(pause || no_tiles) {
212                                 update_status_time(pause, no_tiles);
213
214                                 while(1) {
215                                         double pause_start = time_dt();
216                                         pause_cond.wait(pause_lock);
217                                         paused_time += time_dt() - pause_start;
218
219                                         if(!params.background)
220                                                 progress.set_start_time(start_time + paused_time);
221
222                                         update_status_time(pause, no_tiles);
223                                         progress.set_update();
224
225                                         if(!pause)
226                                                 break;
227                                 }
228                         }
229
230                         if(progress.get_cancel())
231                                 break;
232                 }
233
234                 if(!no_tiles) {
235                         /* update scene */
236                         update_scene();
237
238                         if(device->error_message() != "")
239                                 progress.set_cancel(device->error_message());
240
241                         if(progress.get_cancel())
242                                 break;
243                 }
244
245                 if(!no_tiles) {
246                         /* buffers mutex is locked entirely while rendering each
247                          * sample, and released/reacquired on each iteration to allow
248                          * reset and draw in between */
249                         thread_scoped_lock buffers_lock(buffers_mutex);
250
251                         /* update status and timing */
252                         update_status_time();
253
254                         /* path trace */
255                         path_trace();
256
257                         device->task_wait();
258
259                         if(device->error_message() != "")
260                                 progress.set_cancel(device->error_message());
261
262                         /* update status and timing */
263                         update_status_time();
264
265                         gpu_need_tonemap = true;
266                         gpu_draw_ready = true;
267                         progress.set_update();
268
269                         /* wait for tonemap */
270                         if(!params.background) {
271                                 while(gpu_need_tonemap) {
272                                         if(progress.get_cancel())
273                                                 break;
274
275                                         gpu_need_tonemap_cond.wait(buffers_lock);
276                                 }
277                         }
278
279                         if(device->error_message() != "")
280                                 progress.set_cancel(device->error_message());
281
282                         tiles_written = update_progressive_refine(progress.get_cancel());
283
284                         if(progress.get_cancel())
285                                 break;
286                 }
287         }
288
289         if(!tiles_written)
290                 update_progressive_refine(true);
291 }
292
293 /* CPU Session */
294
295 void Session::reset_cpu(BufferParams& buffer_params, int samples)
296 {
297         thread_scoped_lock reset_lock(delayed_reset.mutex);
298
299         display_outdated = true;
300         reset_time = time_dt();
301
302         delayed_reset.params = buffer_params;
303         delayed_reset.samples = samples;
304         delayed_reset.do_reset = true;
305         device->task_cancel();
306
307         pause_cond.notify_all();
308 }
309
310 bool Session::draw_cpu(BufferParams& buffer_params)
311 {
312         thread_scoped_lock display_lock(display_mutex);
313
314         /* first check we already rendered something */
315         if(display->draw_ready()) {
316                 /* then verify the buffers have the expected size, so we don't
317                  * draw previous results in a resized window */
318                 if(!buffer_params.modified(display->params)) {
319                         display->draw(device);
320
321                         if(display_outdated && (time_dt() - reset_time) > params.text_timeout)
322                                 return false;
323
324                         return true;
325                 }
326         }
327
328         return false;
329 }
330
331 bool Session::acquire_tile(Device *tile_device, RenderTile& rtile)
332 {
333         if(progress.get_cancel()) {
334                 if(params.progressive_refine == false) {
335                         /* for progressive refine current sample should be finished for all tiles */
336                         return false;
337                 }
338         }
339
340         thread_scoped_lock tile_lock(tile_mutex);
341
342         /* get next tile from manager */
343         Tile tile;
344         int device_num = device->device_number(tile_device);
345
346         if(!tile_manager.next_tile(tile, device_num))
347                 return false;
348         
349         /* fill render tile */
350         rtile.x = tile_manager.state.buffer.full_x + tile.x;
351         rtile.y = tile_manager.state.buffer.full_y + tile.y;
352         rtile.w = tile.w;
353         rtile.h = tile.h;
354         rtile.start_sample = tile_manager.state.sample;
355         rtile.num_samples = tile_manager.state.num_samples;
356         rtile.resolution = tile_manager.state.resolution_divider;
357
358         tile_lock.unlock();
359
360         /* in case of a permant buffer, return it, otherwise we will allocate
361          * a new temporary buffer */
362         if(!params.background) {
363                 tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride);
364
365                 rtile.buffer = buffers->buffer.device_pointer;
366                 rtile.rng_state = buffers->rng_state.device_pointer;
367                 rtile.rgba = display->rgba.device_pointer;
368                 rtile.buffers = buffers;
369
370                 device->map_tile(tile_device, rtile);
371
372                 return true;
373         }
374
375         /* fill buffer parameters */
376         BufferParams buffer_params = tile_manager.params;
377         buffer_params.full_x = rtile.x;
378         buffer_params.full_y = rtile.y;
379         buffer_params.width = rtile.w;
380         buffer_params.height = rtile.h;
381
382         buffer_params.get_offset_stride(rtile.offset, rtile.stride);
383
384         RenderBuffers *tilebuffers = new RenderBuffers(tile_device);
385
386         /* allocate buffers */
387         if(params.progressive_refine) {
388                 tile_lock.lock();
389
390                 if(tile_buffers.size() == 0)
391                         tile_buffers.resize(tile_manager.state.num_tiles, NULL);
392
393                 tilebuffers = tile_buffers[tile.index];
394                 if(tilebuffers == NULL) {
395                         tilebuffers = new RenderBuffers(tile_device);
396                         tile_buffers[tile.index] = tilebuffers;
397
398                         tilebuffers->reset(tile_device, buffer_params);
399                 }
400
401                 tile_lock.unlock();
402         }
403         else {
404                 tilebuffers = new RenderBuffers(tile_device);
405
406                 tilebuffers->reset(tile_device, buffer_params);
407         }
408
409         rtile.buffer = tilebuffers->buffer.device_pointer;
410         rtile.rng_state = tilebuffers->rng_state.device_pointer;
411         rtile.rgba = 0;
412         rtile.buffers = tilebuffers;
413
414         return true;
415 }
416
417 void Session::update_tile_sample(RenderTile& rtile)
418 {
419         thread_scoped_lock tile_lock(tile_mutex);
420
421         if(update_render_tile_cb) {
422                 if(params.progressive_refine == false) {
423                         /* todo: optimize this by making it thread safe and removing lock */
424
425                         update_render_tile_cb(rtile);
426                 }
427         }
428
429         update_status_time();
430 }
431
432 void Session::release_tile(RenderTile& rtile)
433 {
434         thread_scoped_lock tile_lock(tile_mutex);
435
436         if(write_render_tile_cb) {
437                 if(params.progressive_refine == false) {
438                         /* todo: optimize this by making it thread safe and removing lock */
439                         write_render_tile_cb(rtile);
440
441                         delete rtile.buffers;
442                 }
443         }
444
445         update_status_time();
446 }
447
448 void Session::run_cpu()
449 {
450         bool tiles_written = false;
451
452         last_update_time = time_dt();
453
454         {
455                 /* reset once to start */
456                 thread_scoped_lock reset_lock(delayed_reset.mutex);
457                 thread_scoped_lock buffers_lock(buffers_mutex);
458                 thread_scoped_lock display_lock(display_mutex);
459
460                 reset_(delayed_reset.params, delayed_reset.samples);
461                 delayed_reset.do_reset = false;
462         }
463
464         while(!progress.get_cancel()) {
465                 /* advance to next tile */
466                 bool no_tiles = !tile_manager.next();
467                 bool need_tonemap = false;
468
469                 if(params.background) {
470                         /* if no work left and in background mode, we can stop immediately */
471                         if(no_tiles) {
472                                 progress.set_status("Finished");
473                                 break;
474                         }
475                 }
476                 else {
477                         /* if in interactive mode, and we are either paused or done for now,
478                          * wait for pause condition notify to wake up again */
479                         thread_scoped_lock pause_lock(pause_mutex);
480
481                         if(pause || no_tiles) {
482                                 update_status_time(pause, no_tiles);
483
484                                 while(1) {
485                                         double pause_start = time_dt();
486                                         pause_cond.wait(pause_lock);
487                                         paused_time += time_dt() - pause_start;
488
489                                         if(!params.background)
490                                                 progress.set_start_time(start_time + paused_time);
491
492                                         update_status_time(pause, no_tiles);
493                                         progress.set_update();
494
495                                         if(!pause)
496                                                 break;
497                                 }
498                         }
499
500                         if(progress.get_cancel())
501                                 break;
502                 }
503
504                 if(!no_tiles) {
505                         /* buffers mutex is locked entirely while rendering each
506                          * sample, and released/reacquired on each iteration to allow
507                          * reset and draw in between */
508                         thread_scoped_lock buffers_lock(buffers_mutex);
509
510                         /* update scene */
511                         update_scene();
512
513                         if(device->error_message() != "")
514                                 progress.set_cancel(device->error_message());
515
516                         if(progress.get_cancel())
517                                 break;
518
519                         /* update status and timing */
520                         update_status_time();
521
522                         /* path trace */
523                         path_trace();
524
525                         /* update status and timing */
526                         update_status_time();
527
528                         if(!params.background)
529                                 need_tonemap = true;
530
531                         if(device->error_message() != "")
532                                 progress.set_cancel(device->error_message());
533                 }
534
535                 device->task_wait();
536
537                 {
538                         thread_scoped_lock reset_lock(delayed_reset.mutex);
539                         thread_scoped_lock buffers_lock(buffers_mutex);
540                         thread_scoped_lock display_lock(display_mutex);
541
542                         if(delayed_reset.do_reset) {
543                                 /* reset rendering if request from main thread */
544                                 delayed_reset.do_reset = false;
545                                 reset_(delayed_reset.params, delayed_reset.samples);
546                         }
547                         else if(need_tonemap) {
548                                 /* tonemap only if we do not reset, we don't we don't
549                                  * wan't to show the result of an incomplete sample*/
550                                 tonemap();
551                         }
552
553                         if(device->error_message() != "")
554                                 progress.set_cancel(device->error_message());
555
556                         tiles_written = update_progressive_refine(progress.get_cancel());
557                 }
558
559                 progress.set_update();
560         }
561
562         if(!tiles_written)
563                 update_progressive_refine(true);
564 }
565
566 void Session::run()
567 {
568         /* load kernels */
569         if(!kernels_loaded) {
570                 progress.set_status("Loading render kernels (may take a few minutes the first time)");
571
572                 if(!device->load_kernels(params.experimental)) {
573                         string message = device->error_message();
574                         if(message == "")
575                                 message = "Failed loading render kernel, see console for errors";
576
577                         progress.set_status("Error", message);
578                         progress.set_update();
579                         return;
580                 }
581
582                 kernels_loaded = true;
583         }
584
585         /* session thread loop */
586         progress.set_status("Waiting for render to start");
587
588         /* run */
589         if(!progress.get_cancel()) {
590                 /* reset number of rendered samples */
591                 progress.reset_sample();
592
593                 if(device_use_gl)
594                         run_gpu();
595                 else
596                         run_cpu();
597         }
598
599         /* progress update */
600         if(progress.get_cancel())
601                 progress.set_status("Cancel", progress.get_cancel_message());
602         else
603                 progress.set_update();
604 }
605
606 bool Session::draw(BufferParams& buffer_params)
607 {
608         if(device_use_gl)
609                 return draw_gpu(buffer_params);
610         else
611                 return draw_cpu(buffer_params);
612 }
613
614 void Session::reset_(BufferParams& buffer_params, int samples)
615 {
616         if(buffers) {
617                 if(buffer_params.modified(buffers->params)) {
618                         gpu_draw_ready = false;
619                         buffers->reset(device, buffer_params);
620                         display->reset(device, buffer_params);
621                 }
622         }
623
624         tile_manager.reset(buffer_params, samples);
625
626         start_time = time_dt();
627         preview_time = 0.0;
628         paused_time = 0.0;
629
630         if(!params.background)
631                 progress.set_start_time(start_time + paused_time);
632 }
633
634 void Session::reset(BufferParams& buffer_params, int samples)
635 {
636         if(device_use_gl)
637                 reset_gpu(buffer_params, samples);
638         else
639                 reset_cpu(buffer_params, samples);
640 }
641
642 void Session::set_samples(int samples)
643 {
644         if(samples != params.samples) {
645                 params.samples = samples;
646                 tile_manager.set_samples(samples);
647
648                 {
649                         thread_scoped_lock pause_lock(pause_mutex);
650                 }
651                 pause_cond.notify_all();
652         }
653 }
654
655 void Session::set_pause(bool pause_)
656 {
657         bool notify = false;
658
659         {
660                 thread_scoped_lock pause_lock(pause_mutex);
661
662                 if(pause != pause_) {
663                         pause = pause_;
664                         notify = true;
665                 }
666         }
667
668         if(notify)
669                 pause_cond.notify_all();
670 }
671
672 void Session::wait()
673 {
674         session_thread->join();
675         delete session_thread;
676
677         session_thread = NULL;
678 }
679
680 void Session::update_scene()
681 {
682         thread_scoped_lock scene_lock(scene->mutex);
683
684         /* update camera if dimensions changed for progressive render. the camera
685          * knows nothing about progressive or cropped rendering, it just gets the
686          * image dimensions passed in */
687         Camera *cam = scene->camera;
688         int width = tile_manager.state.buffer.full_width;
689         int height = tile_manager.state.buffer.full_height;
690
691         if(width != cam->width || height != cam->height) {
692                 cam->width = width;
693                 cam->height = height;
694                 cam->tag_update();
695         }
696
697         /* update scene */
698         if(scene->need_update()) {
699                 progress.set_status("Updating Scene");
700                 scene->device_update(device, progress);
701         }
702 }
703
704 void Session::update_status_time(bool show_pause, bool show_done)
705 {
706         int sample = tile_manager.state.sample;
707         int resolution = tile_manager.state.resolution_divider;
708         int num_tiles = tile_manager.state.num_tiles;
709         int tile = tile_manager.state.num_rendered_tiles;
710
711         /* update status */
712         string status, substatus;
713
714         if(!params.progressive) {
715                 bool is_gpu = params.device.type == DEVICE_CUDA || params.device.type == DEVICE_OPENCL;
716                 bool is_multidevice = params.device.multi_devices.size() > 1;
717                 bool is_cpu = params.device.type == DEVICE_CPU;
718
719                 substatus = string_printf("Path Tracing Tile %d/%d", tile, num_tiles);
720
721                 if((is_gpu && !is_multidevice) || (is_cpu && num_tiles == 1)) {
722                         /* when rendering on GPU multithreading happens within single tile, as in
723                          * tiles are handling sequentially and in this case we could display
724                          * currently rendering sample number
725                          * this helps a lot from feedback point of view.
726                          * also display the info on CPU, when using 1 tile only
727                          */
728
729                         int sample = progress.get_sample(), num_samples = tile_manager.state.num_samples;
730
731                         if(tile > 1) {
732                                 /* sample counter is global for all tiles, subtract samples
733                                  * from already finished tiles to get sample counter for
734                                  * current tile only
735                                  */
736                                 sample -= (tile - 1) * num_samples;
737                         }
738
739                         substatus += string_printf(", Sample %d/%d", sample, num_samples);
740                 }
741         }
742         else if(params.samples == INT_MAX)
743                 substatus = string_printf("Path Tracing Sample %d", sample+1);
744         else
745                 substatus = string_printf("Path Tracing Sample %d/%d", sample+1, params.samples);
746         
747         if(show_pause)
748                 status = "Paused";
749         else if(show_done)
750                 status = "Done";
751         else
752                 status = "Rendering";
753
754         progress.set_status(status, substatus);
755
756         /* update timing */
757         if(preview_time == 0.0 && resolution == 1)
758                 preview_time = time_dt();
759         
760         double tile_time = (tile == 0)? 0.0: (time_dt() - preview_time - paused_time)/(sample);
761
762         /* negative can happen when we pause a bit before rendering, can discard that */
763         if(preview_time < 0.0) preview_time = 0.0;
764
765         progress.set_tile(tile, tile_time);
766 }
767
768 void Session::update_progress_sample()
769 {
770         progress.increment_sample();
771 }
772
773 void Session::path_trace()
774 {
775         /* add path trace task */
776         DeviceTask task(DeviceTask::PATH_TRACE);
777         
778         task.acquire_tile = function_bind(&Session::acquire_tile, this, _1, _2);
779         task.release_tile = function_bind(&Session::release_tile, this, _1);
780         task.get_cancel = function_bind(&Progress::get_cancel, &this->progress);
781         task.update_tile_sample = function_bind(&Session::update_tile_sample, this, _1);
782         task.update_progress_sample = function_bind(&Session::update_progress_sample, this);
783         task.need_finish_queue = params.progressive_refine;
784
785         device->task_add(task);
786 }
787
788 void Session::tonemap()
789 {
790         /* add tonemap task */
791         DeviceTask task(DeviceTask::TONEMAP);
792
793         task.x = tile_manager.state.buffer.full_x;
794         task.y = tile_manager.state.buffer.full_y;
795         task.w = tile_manager.state.buffer.width;
796         task.h = tile_manager.state.buffer.height;
797         task.rgba = display->rgba.device_pointer;
798         task.buffer = buffers->buffer.device_pointer;
799         task.sample = tile_manager.state.sample;
800         task.resolution = tile_manager.state.resolution_divider;
801         tile_manager.state.buffer.get_offset_stride(task.offset, task.stride);
802
803         if(task.w > 0 && task.h > 0) {
804                 device->task_add(task);
805                 device->task_wait();
806
807                 /* set display to new size */
808                 display->draw_set(task.w, task.h);
809         }
810
811         display_outdated = false;
812 }
813
814 bool Session::update_progressive_refine(bool cancel)
815 {
816         int sample = tile_manager.state.sample + 1;
817         bool write = sample == params.samples || cancel;
818
819         double current_time = time_dt();
820
821         if (current_time - last_update_time < 1.0f) {
822                 /* if last sample was processed, we need to write buffers anyway  */
823                 if (!write)
824                         return false;
825         }
826
827         if(params.progressive_refine) {
828                 foreach(RenderBuffers *buffers, tile_buffers) {
829                         RenderTile rtile;
830                         rtile.buffers = buffers;
831                         rtile.sample = sample;
832
833                         if(write)
834                                 write_render_tile_cb(rtile);
835                         else
836                                 update_render_tile_cb(rtile);
837                 }
838         }
839
840         last_update_time = current_time;
841
842         return write;
843 }
844
845 CCL_NAMESPACE_END