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