~siretart/ubuntu/utopic/blender/libav10

« back to all changes in this revision

Viewing changes to intern/cycles/render/session.cpp

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2012-07-23 08:54:18 UTC
  • mfrom: (14.2.16 sid)
  • mto: (14.2.19 sid)
  • mto: This revision was merged to the branch mainline in revision 42.
  • Revision ID: package-import@ubuntu.com-20120723085418-9foz30v6afaf5ffs
Tags: 2.63a-2
* debian/: Cycles support added (Closes: #658075)
  For now, this top feature has been enabled only
  on [any-amd64 any-i386] architectures because
  of OpenImageIO failing on all others
* debian/: scripts installation path changed
  from /usr/lib to /usr/share:
  + debian/patches/: patchset re-worked for path changing
  + debian/control: "Breaks" field added on yafaray-exporter

Show diffs side-by-side

added added

removed removed

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