svn merge ^/trunk/blender -r49763:49774
[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
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                 if(device_use_gl)
536                         run_gpu();
537                 else
538                         run_cpu();
539         }
540
541         /* progress update */
542         if(progress.get_cancel())
543                 progress.set_status("Cancel", progress.get_cancel_message());
544         else
545                 progress.set_update();
546 }
547
548 bool Session::draw(BufferParams& buffer_params)
549 {
550         if(device_use_gl)
551                 return draw_gpu(buffer_params);
552         else
553                 return draw_cpu(buffer_params);
554 }
555
556 void Session::reset_(BufferParams& buffer_params, int samples)
557 {
558         if(buffers) {
559                 if(buffer_params.modified(buffers->params)) {
560                         gpu_draw_ready = false;
561                         buffers->reset(device, buffer_params);
562                         display->reset(device, buffer_params);
563                 }
564         }
565
566         tile_manager.reset(buffer_params, samples);
567
568         start_time = time_dt();
569         preview_time = 0.0;
570         paused_time = 0.0;
571
572         if(!params.background)
573                 progress.set_start_time(start_time + paused_time);
574 }
575
576 void Session::reset(BufferParams& buffer_params, int samples)
577 {
578         if(device_use_gl)
579                 reset_gpu(buffer_params, samples);
580         else
581                 reset_cpu(buffer_params, samples);
582 }
583
584 void Session::set_samples(int samples)
585 {
586         if(samples != params.samples) {
587                 params.samples = samples;
588                 tile_manager.set_samples(samples);
589
590                 {
591                         thread_scoped_lock pause_lock(pause_mutex);
592                 }
593                 pause_cond.notify_all();
594         }
595 }
596
597 void Session::set_pause(bool pause_)
598 {
599         bool notify = false;
600
601         {
602                 thread_scoped_lock pause_lock(pause_mutex);
603
604                 if(pause != pause_) {
605                         pause = pause_;
606                         notify = true;
607                 }
608         }
609
610         if(notify)
611                 pause_cond.notify_all();
612 }
613
614 void Session::wait()
615 {
616         session_thread->join();
617         delete session_thread;
618
619         session_thread = NULL;
620 }
621
622 void Session::update_scene()
623 {
624         thread_scoped_lock scene_lock(scene->mutex);
625
626         /* update camera if dimensions changed for progressive render. the camera
627          * knows nothing about progressive or cropped rendering, it just gets the
628          * image dimensions passed in */
629         Camera *cam = scene->camera;
630         int width = tile_manager.state.buffer.full_width;
631         int height = tile_manager.state.buffer.full_height;
632
633         if(width != cam->width || height != cam->height) {
634                 cam->width = width;
635                 cam->height = height;
636                 cam->tag_update();
637         }
638
639         /* update scene */
640         if(scene->need_update()) {
641                 progress.set_status("Updating Scene");
642                 scene->device_update(device, progress);
643         }
644 }
645
646 void Session::update_status_time(bool show_pause, bool show_done)
647 {
648         int sample = tile_manager.state.sample;
649         int resolution = tile_manager.state.resolution;
650         int num_tiles = tile_manager.state.num_tiles;
651         int tile = tile_manager.state.num_rendered_tiles;
652
653         /* update status */
654         string status, substatus;
655
656         if(!params.progressive) {
657                 substatus = string_printf("Path Tracing Tile %d/%d", tile, num_tiles);
658
659                 if(params.device.type == DEVICE_CUDA || params.device.type == DEVICE_OPENCL ||
660                         (params.device.type == DEVICE_CPU && num_tiles == 1)) {
661                         /* when rendering on GPU multithreading happens within single tile, as in
662                          * tiles are handling sequentially and in this case we could display
663                          * currently rendering sample number
664                          * this helps a lot from feedback point of view.
665                          * also display the info on CPU, when using 1 tile only
666                          */
667
668                         int sample = progress.get_sample(), num_samples = tile_manager.state.num_samples;
669
670                         if(tile > 1) {
671                                 /* sample counter is global for all tiles, subtract samples
672                                  * from already finished tiles to get sample counter for
673                                  * current tile only
674                                  */
675                                 sample -= (tile - 1) * num_samples;
676                         }
677
678                         substatus += string_printf(", Sample %d/%d", sample, num_samples);
679                 }
680         }
681         else if(params.samples == INT_MAX)
682                 substatus = string_printf("Path Tracing Sample %d", sample+1);
683         else
684                 substatus = string_printf("Path Tracing Sample %d/%d", sample+1, params.samples);
685         
686         if(show_pause)
687                 status = "Paused";
688         else if(show_done)
689                 status = "Done";
690         else
691                 status = "Rendering";
692
693         progress.set_status(status, substatus);
694
695         /* update timing */
696         if(preview_time == 0.0 && resolution == 1)
697                 preview_time = time_dt();
698         
699         double tile_time = (tile == 0)? 0.0: (time_dt() - preview_time - paused_time)/(sample);
700
701         /* negative can happen when we pause a bit before rendering, can discard that */
702         if(preview_time < 0.0) preview_time = 0.0;
703
704         progress.set_tile(tile, tile_time);
705 }
706
707 void Session::update_progress_sample()
708 {
709         progress.increment_sample();
710 }
711
712 void Session::path_trace()
713 {
714         /* add path trace task */
715         DeviceTask task(DeviceTask::PATH_TRACE);
716         
717         task.acquire_tile = function_bind(&Session::acquire_tile, this, _1, _2);
718         task.release_tile = function_bind(&Session::release_tile, this, _1);
719         task.get_cancel = function_bind(&Progress::get_cancel, &this->progress);
720         task.update_tile_sample = function_bind(&Session::update_tile_sample, this, _1);
721         task.update_progress_sample = function_bind(&Session::update_progress_sample, this);
722
723         device->task_add(task);
724 }
725
726 void Session::tonemap()
727 {
728         /* add tonemap task */
729         DeviceTask task(DeviceTask::TONEMAP);
730
731         task.x = tile_manager.state.buffer.full_x;
732         task.y = tile_manager.state.buffer.full_y;
733         task.w = tile_manager.state.buffer.width;
734         task.h = tile_manager.state.buffer.height;
735         task.rgba = display->rgba.device_pointer;
736         task.buffer = buffers->buffer.device_pointer;
737         task.sample = tile_manager.state.sample;
738         task.resolution = tile_manager.state.resolution;
739         tile_manager.state.buffer.get_offset_stride(task.offset, task.stride);
740
741         if(task.w > 0 && task.h > 0) {
742                 device->task_add(task);
743                 device->task_wait();
744
745                 /* set display to new size */
746                 display->draw_set(task.w, task.h);
747         }
748
749         display_outdated = false;
750 }
751
752 CCL_NAMESPACE_END
753