Tomato mango request: do not start compositing on file load
[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_buffers_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::release_tile(RenderTile& rtile)
377 {
378         thread_scoped_lock tile_lock(tile_mutex);
379
380         if(write_render_buffers_cb) {
381                 /* todo: optimize this by making it thread safe and removing lock */
382                 if(!progress.get_cancel())
383                         write_render_buffers_cb(rtile.buffers);
384                 delete rtile.buffers;
385         }
386
387         update_status_time();
388 }
389
390 void Session::run_cpu()
391 {
392         {
393                 /* reset once to start */
394                 thread_scoped_lock reset_lock(delayed_reset.mutex);
395                 thread_scoped_lock buffers_lock(buffers_mutex);
396                 thread_scoped_lock display_lock(display_mutex);
397
398                 reset_(delayed_reset.params, delayed_reset.samples);
399                 delayed_reset.do_reset = false;
400         }
401
402         while(!progress.get_cancel()) {
403                 /* advance to next tile */
404                 bool no_tiles = !tile_manager.next();
405                 bool need_tonemap = false;
406
407                 if(params.background) {
408                         /* if no work left and in background mode, we can stop immediately */
409                         if(no_tiles) {
410                                 progress.set_status("Finished");
411                                 break;
412                         }
413                 }
414                 else {
415                         /* if in interactive mode, and we are either paused or done for now,
416                          * wait for pause condition notify to wake up again */
417                         thread_scoped_lock pause_lock(pause_mutex);
418
419                         if(pause || no_tiles) {
420                                 update_status_time(pause, no_tiles);
421
422                                 while(1) {
423                                         double pause_start = time_dt();
424                                         pause_cond.wait(pause_lock);
425                                         paused_time += time_dt() - pause_start;
426
427                                         if(!params.background)
428                                                 progress.set_start_time(start_time + paused_time);
429
430                                         update_status_time(pause, no_tiles);
431                                         progress.set_update();
432
433                                         if(!pause)
434                                                 break;
435                                 }
436                         }
437
438                         if(progress.get_cancel())
439                                 break;
440                 }
441
442                 if(!no_tiles) {
443                         /* buffers mutex is locked entirely while rendering each
444                          * sample, and released/reacquired on each iteration to allow
445                          * reset and draw in between */
446                         thread_scoped_lock buffers_lock(buffers_mutex);
447
448                         /* update scene */
449                         update_scene();
450
451                         if(device->error_message() != "")
452                                 progress.set_cancel(device->error_message());
453
454                         if(progress.get_cancel())
455                                 break;
456
457                         /* update status and timing */
458                         update_status_time();
459
460                         /* path trace */
461                         path_trace();
462
463                         /* update status and timing */
464                         update_status_time();
465
466                         if(!params.background)
467                                 need_tonemap = true;
468
469                         if(device->error_message() != "")
470                                 progress.set_cancel(device->error_message());
471                 }
472
473                 device->task_wait();
474
475                 {
476                         thread_scoped_lock reset_lock(delayed_reset.mutex);
477                         thread_scoped_lock buffers_lock(buffers_mutex);
478                         thread_scoped_lock display_lock(display_mutex);
479
480                         if(delayed_reset.do_reset) {
481                                 /* reset rendering if request from main thread */
482                                 delayed_reset.do_reset = false;
483                                 reset_(delayed_reset.params, delayed_reset.samples);
484                         }
485                         else if(need_tonemap) {
486                                 /* tonemap only if we do not reset, we don't we don't
487                                  * wan't to show the result of an incomplete sample*/
488                                 tonemap();
489                         }
490
491                         if(device->error_message() != "")
492                                 progress.set_cancel(device->error_message());
493                 }
494
495                 progress.set_update();
496         }
497 }
498
499 void Session::run()
500 {
501         /* load kernels */
502         if(!kernels_loaded) {
503                 progress.set_status("Loading render kernels (may take a few minutes the first time)");
504
505                 if(!device->load_kernels(params.experimental)) {
506                         string message = device->error_message();
507                         if(message == "")
508                                 message = "Failed loading render kernel, see console for errors";
509
510                         progress.set_status("Error", message);
511                         progress.set_update();
512                         return;
513                 }
514
515                 kernels_loaded = true;
516         }
517
518         /* session thread loop */
519         progress.set_status("Waiting for render to start");
520
521         /* run */
522         if(!progress.get_cancel()) {
523                 if(device_use_gl)
524                         run_gpu();
525                 else
526                         run_cpu();
527         }
528
529         /* progress update */
530         if(progress.get_cancel())
531                 progress.set_status("Cancel", progress.get_cancel_message());
532         else
533                 progress.set_update();
534 }
535
536 bool Session::draw(BufferParams& buffer_params)
537 {
538         if(device_use_gl)
539                 return draw_gpu(buffer_params);
540         else
541                 return draw_cpu(buffer_params);
542 }
543
544 void Session::reset_(BufferParams& buffer_params, int samples)
545 {
546         if(buffers) {
547                 if(buffer_params.modified(buffers->params)) {
548                         gpu_draw_ready = false;
549                         buffers->reset(device, buffer_params);
550                         display->reset(device, buffer_params);
551                 }
552         }
553
554         tile_manager.reset(buffer_params, samples);
555
556         start_time = time_dt();
557         preview_time = 0.0;
558         paused_time = 0.0;
559         sample = 0;
560
561         if(!params.background)
562                 progress.set_start_time(start_time + paused_time);
563 }
564
565 void Session::reset(BufferParams& buffer_params, int samples)
566 {
567         if(device_use_gl)
568                 reset_gpu(buffer_params, samples);
569         else
570                 reset_cpu(buffer_params, samples);
571 }
572
573 void Session::set_samples(int samples)
574 {
575         if(samples != params.samples) {
576                 params.samples = samples;
577                 tile_manager.set_samples(samples);
578
579                 {
580                         thread_scoped_lock pause_lock(pause_mutex);
581                 }
582                 pause_cond.notify_all();
583         }
584 }
585
586 void Session::set_pause(bool pause_)
587 {
588         bool notify = false;
589
590         {
591                 thread_scoped_lock pause_lock(pause_mutex);
592
593                 if(pause != pause_) {
594                         pause = pause_;
595                         notify = true;
596                 }
597         }
598
599         if(notify)
600                 pause_cond.notify_all();
601 }
602
603 void Session::wait()
604 {
605         session_thread->join();
606         delete session_thread;
607
608         session_thread = NULL;
609 }
610
611 void Session::update_scene()
612 {
613         thread_scoped_lock scene_lock(scene->mutex);
614
615         /* update camera if dimensions changed for progressive render. the camera
616          * knows nothing about progressive or cropped rendering, it just gets the
617          * image dimensions passed in */
618         Camera *cam = scene->camera;
619         int width = tile_manager.state.buffer.full_width;
620         int height = tile_manager.state.buffer.full_height;
621
622         if(width != cam->width || height != cam->height) {
623                 cam->width = width;
624                 cam->height = height;
625                 cam->tag_update();
626         }
627
628         /* update scene */
629         if(scene->need_update()) {
630                 progress.set_status("Updating Scene");
631                 scene->device_update(device, progress);
632         }
633 }
634
635 void Session::update_status_time(bool show_pause, bool show_done)
636 {
637         int sample = tile_manager.state.sample;
638         int num_samples = tile_manager.state.num_samples;
639         int resolution = tile_manager.state.resolution;
640         int num_tiles = tile_manager.state.num_tiles;
641         int tile = num_tiles - tile_manager.state.tiles.size();
642
643         /* update status */
644         string status, substatus;
645
646         if(!params.progressive)
647                 substatus = string_printf("Path Tracing Tile %d/%d", tile, num_tiles);
648         else if(params.samples == INT_MAX)
649                 substatus = string_printf("Path Tracing Sample %d", sample+1);
650         else
651                 substatus = string_printf("Path Tracing Sample %d/%d", sample+1, params.samples);
652         
653         if(show_pause)
654                 status = "Paused";
655         else if(show_done)
656                 status = "Done";
657         else
658                 status = "Rendering";
659
660         progress.set_status(status, substatus);
661
662         /* update timing */
663         if(preview_time == 0.0 && resolution == 1)
664                 preview_time = time_dt();
665         
666         double sample_time = (sample == 0)? 0.0: (time_dt() - preview_time - paused_time)/(sample);
667
668         /* negative can happen when we pause a bit before rendering, can discard that */
669         if(preview_time < 0.0) preview_time = 0.0;
670
671         progress.set_sample(sample + num_samples, sample_time);
672 }
673
674 void Session::path_trace()
675 {
676         /* add path trace task */
677         DeviceTask task(DeviceTask::PATH_TRACE);
678         
679         task.acquire_tile = function_bind(&Session::acquire_tile, this, _1, _2);
680         task.release_tile = function_bind(&Session::release_tile, this, _1);
681
682         device->task_add(task);
683 }
684
685 void Session::tonemap()
686 {
687         /* add tonemap task */
688         DeviceTask task(DeviceTask::TONEMAP);
689
690         task.x = tile_manager.state.buffer.full_x;
691         task.y = tile_manager.state.buffer.full_y;
692         task.w = tile_manager.state.buffer.width;
693         task.h = tile_manager.state.buffer.height;
694         task.rgba = display->rgba.device_pointer;
695         task.buffer = buffers->buffer.device_pointer;
696         task.sample = tile_manager.state.sample;
697         task.resolution = tile_manager.state.resolution;
698         tile_manager.state.buffer.get_offset_stride(task.offset, task.stride);
699
700         if(task.w > 0 && task.h > 0) {
701                 device->task_add(task);
702                 device->task_wait();
703
704                 /* set display to new size */
705                 display->draw_set(task.w, task.h);
706         }
707
708         display_outdated = false;
709 }
710
711 CCL_NAMESPACE_END
712