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