opengljobprocessor.cpp 6.59 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// ================================================================================================
// 
// This file is part of the TUMVis Visualization Framework.
// 
// If not explicitly stated otherwise: Copyright (C) 2012, all rights reserved,
//      Christian Schulte zu Berge (christian.szb@in.tum.de)
//      Chair for Computer Aided Medical Procedures
//      Technische Universitt Mnchen
//      Boltzmannstr. 3, 85748 Garching b. Mnchen, Germany
// 
// The licensing of this softare is not yet resolved. Until then, redistribution in source or
// binary forms outside the CAMP chair is not permitted, unless explicitly stated in legal form.
// However, the names of the original authors and the above copyright notice must retain in its
// original state in any case.
// 
// Legal disclaimer provided by the BSD license:
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// 
// ================================================================================================

#include "opengljobprocessor.h"

#include "tgt/assert.h"
#include "tgt/qt/qtcontextmanager.h"
#include "core/tools/job.h"

namespace TUMVis {

    OpenGLJobProcessor::OpenGLJobProcessor()
        : _currentContext(0)
39
        , _startTimeCurrentContext(0)
40
41
42
43
    {
    }

    OpenGLJobProcessor::~OpenGLJobProcessor() {
44

45
46
47
48
49
50
51
52
53
54
55
56
57
    }

    void OpenGLJobProcessor::stop() {
        _stopExecution = true;
        _evaluationCondition.notify_all();

        Runnable::stop();
    }

    void OpenGLJobProcessor::run() {
        std::unique_lock<tbb::mutex> lock(CtxtMgr.getGlMutex());

        while (! _stopExecution) {
58
59
60
61
62
63
64
65
66
67
68
69
70
71
            // this is a simple round-robing scheduling between all contexts:
            bool hadWork = false;
            clock_t maxTimePerContext = 30 / _contexts.size();

            for (size_t i = 0; i < _contexts.size(); ++i) {
                _startTimeCurrentContext = clock() * 1000 / CLOCKS_PER_SEC;
                tgt::GLCanvas* context = _contexts[i];

                tbb::concurrent_hash_map<tgt::GLCanvas*, PerContextJobQueue*>::const_accessor a;
                if (!_contextQueueMap.find(a, context)) {
                    tgtAssert(false, "Should not reach this: Did not find context in contextQueueMap!");
                    break;
                }

schultezub's avatar
schultezub committed
72
                // avoid expensive context-switches for contexts without oending jobs.
73
74
75
                if (a->second->empty())
                    continue;

schultezub's avatar
schultezub committed
76
                // perform context switch if necessary
77
                if (_currentContext != context) {
78
79
80
81
                    if (_currentContext != 0) {
                        glFinish();
                        LGL_ERROR;
                    }
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
                    context->getContext()->acquire();
                    _currentContext = context;
                }

                // now comes the per-context scheduling strategy:
                // first: perform as much serial jobs as possible:
                AbstractJob* jobToDo = 0;
                while ((clock() * 1000 / CLOCKS_PER_SEC) - _startTimeCurrentContext < maxTimePerContext) {
                    // try fetch a job
                    if (! a->second->_serialJobs.try_pop(jobToDo)) {
                        // no job to do, exit the while loop
                        break;
                    }
                    // execute and delete the job
                    jobToDo->execute();
                    delete jobToDo;
                }

                // second: execute one low-prio job if existant
                if (a->second->_lowPriorityJobs.try_pop(jobToDo)) {
                    jobToDo->execute();
                    delete jobToDo;
104
105
                }

106
107
108
109
110
111
112
113
114
                // third: execute paint job
                if ((jobToDo = a->second->_paintJob) != 0) {
                    jobToDo->execute();
                    delete jobToDo;
                    a->second->_paintJob = 0;
                }

                // update hadWork flag
                hadWork = (jobToDo != 0);
115
116
            }

117
118
            if (! hadWork) {
                CtxtMgr.releaseCurrentContext();
119
                _evaluationCondition.wait(lock);
120
121
                _currentContext->getContext()->acquire();
            }
122
123
124
125
126
127
        }

        // release OpenGL context, so that other threads can access it
        CtxtMgr.releaseCurrentContext();
    }

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
    void OpenGLJobProcessor::enqueueJob(tgt::GLCanvas* canvas, AbstractJob* job, JobType priority) {
        tbb::concurrent_hash_map<tgt::GLCanvas*, PerContextJobQueue*>::const_accessor a;
        if (_contextQueueMap.find(a, canvas)) {
            switch (priority) {
            case PaintJob:
                if (a->second->_paintJob != 0)
                    delete a->second->_paintJob;
                a->second->_paintJob = job;
                break;
            case SerialJob:
                a->second->_serialJobs.push(job);
                break;
            case LowPriorityJob:
                a->second->_lowPriorityJobs.push(job);
                break;
            default:
                tgtAssert(false, "Should not reach this - wrong job type!");
                break;
            } 
        }
        else {
            tgtAssert(false, "Specified context not found. Context must be registered before they can have jobs.");
        }
151
152
153

        _evaluationCondition.notify_all();
    }
154
155
156
157
158
159
160
161
162
163
164
165
166

    void OpenGLJobProcessor::registerContext(tgt::GLCanvas* context) {
#ifdef TUMVIS_DEBUG
        tbb::concurrent_hash_map<tgt::GLCanvas*, PerContextJobQueue*>::const_accessor a;
        if (_contextQueueMap.find(a, context))
            tgtAssert(false, "Contexts shall only be registered once!");
#endif

        PerContextJobQueue* newQueue = new PerContextJobQueue;
        _contextQueueMap.insert(std::make_pair(context, newQueue));
        _contexts.push_back(context);
    }

167
168
}