Cycles: border render now works in the viewport, when looking through the
[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                                    want 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