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