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