abstractpipeline.cpp 12.4 KB
Newer Older
1

2 3
// ================================================================================================
// 
schultezub's avatar
schultezub committed
4
// This file is part of the CAMPVis Software Framework.
5
// 
6
// If not explicitly stated otherwise: Copyright (C) 2012-2015, all rights reserved,
schultezub's avatar
schultezub committed
7
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
8
//      Chair for Computer Aided Medical Procedures
9 10
//      Technische Universitaet Muenchen
//      Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
11
// 
schultezub's avatar
schultezub committed
12
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
13
// 
14 15 16 17
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 
// except in compliance with the License. You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
18
// 
19 20 21 22
// Unless required by applicable law or agreed to in writing, software distributed under the 
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
// either express or implied. See the License for the specific language governing permissions 
// and limitations under the License.
23 24 25
// 
// ================================================================================================

26
#include "abstractpipeline.h"
schultezub's avatar
schultezub committed
27

28 29
#include <tbb/tick_count.h>

30 31 32 33
#include "cgt/exception.h"
#include "cgt/glcanvas.h"
#include "cgt/glcontextmanager.h"
#include "cgt/painter.h"
34
#include "cgt/cgt_gl.h"
35 36

#include "core/pipeline/visualizationprocessor.h"
37
#include "core/pipeline/abstractprocessor.h"
38

39

schultezub's avatar
schultezub committed
40 41
namespace campvis {
    const std::string AbstractPipeline::loggerCat_ = "CAMPVis.core.datastructures.AbstractPipeline";
42

43
    AbstractPipeline::AbstractPipeline(DataContainer& dc) 
44
        : HasPropertyCollection()
45 46
        , cgt::EventHandler()
        , cgt::EventListener()
47
        , _dataContainer(&dc)
48
        , _canvas(0)
49
        , _canvasSize("CanvasSize", "Canvas Size", cgt::ivec2(128, 128), cgt::ivec2(1, 1), cgt::ivec2(4096, 4096))
50 51
        , _ignoreCanvasSizeUpdate(false)
        , _renderTargetID("renderTargetID", "Render Target ID", "AbstractPipeline.renderTarget", DataNameProperty::READ)
52
        , p_showFullscreen("ShowFullscreen", "Show Fullscreen", false)
schultezub's avatar
 
schultezub committed
53
    {
54
        cgtAssert(_dataContainer != nullptr, "Pointer to the DataContainer for this pipeline must not be 0!");
55

56 57
        _painter.reset(new PipelinePainter(nullptr, this));

58
        _enabled = false;
59
        _pipelineDirty = true;
60

61 62
        addProperty(_renderTargetID);
        addProperty(_canvasSize);
63
        addProperty(p_showFullscreen);
schultezub's avatar
 
schultezub committed
64 65 66 67 68
    }

    AbstractPipeline::~AbstractPipeline() {
    }

69
    void AbstractPipeline::init() {
70 71
        setThreadName(std::string("Pipeline ") + getName());

72
        _dataContainer->s_dataAdded.connect(this, &AbstractPipeline::onDataContainerDataAdded);
73

74
        _painter->init();
schultezub's avatar
schultezub committed
75 76
        initAllProperties();

77
        // initialize all processors:
schultezub's avatar
schultezub committed
78 79 80 81
        for (std::vector<AbstractProcessor*>::iterator it = _processors.begin(); it != _processors.end(); ++it) {
            try {
                (*it)->init();
            }
82
            catch (cgt::Exception& e) {
schultezub's avatar
schultezub committed
83 84 85
                LERROR("Caught Exception during initialization of processor: " << e.what());
            }
        }
86

87 88
        p_showFullscreen.s_changed.connect(this, &AbstractPipeline::onFullscreenChanged);

89 90
        // use trigger signal to enforce blocking call
        s_init.triggerSignal();
91
    }
schultezub's avatar
schultezub committed
92

93
    void AbstractPipeline::deinit() {
94
        _dataContainer->s_dataAdded.disconnect(this);
95

96 97 98
        // use trigger signal to enforce blocking call
        s_deinit.triggerSignal();

schultezub's avatar
schultezub committed
99
        deinitAllProperties();
100
        _painter->deinit();
schultezub's avatar
schultezub committed
101

102 103 104
        // deinitialize all processors:
        for (std::vector<AbstractProcessor*>::iterator it = _processors.begin(); it != _processors.end(); ++it) {
            try {
schultezub's avatar
schultezub committed
105
                (*it)->s_invalidated.disconnect(this);
106 107
                (*it)->deinit();
            }
108
            catch (cgt::Exception& e) {
109 110 111
                LERROR("Caught Exception during deinitialization of processor: " << e.what());
            }
        }
112

113

114
        // clear DataContainer
115
        _dataContainer->clear();
116 117
    }

118
    void AbstractPipeline::run() {
119 120
        std::unique_lock<std::mutex> lock(*cgt::GlContextManager::getRef().getGlMutexForContext(_canvas));
        cgt::GlContextManager::getRef().acquireContext(_canvas, false);
121 122 123 124 125 126 127 128 129 130 131 132 133

        while (! _stopExecution) {
            if (_enabled && _pipelineDirty) {
                // mark pipeline as not dirty
                _pipelineDirty = false;

                // execute pipeline
                executePipeline();

                // paint on canvas
                _canvas->getPainter()->paint();
            }

134
            if (!_stopExecution && (!_enabled || !_pipelineDirty)) {
135
                cgt::GlContextManager::getRef().releaseContext(_canvas, false);
136
                _evaluationCondition.wait(lock);
137
                cgt::GlContextManager::getRef().acquireContext(_canvas, false);
138 139 140
            }
        }

141
        cgt::GlContextManager::getRef().releaseContext(_canvas, false);
142 143
    }

schultezub's avatar
schultezub committed
144
    void AbstractPipeline::onPropertyChanged(const AbstractProperty* prop) {
145
        if (prop == &_renderTargetID) {
146
            setPipelineDirty();
147
        }
148
        else if (prop == &_canvasSize && _canvas != nullptr && !_ignoreCanvasSizeUpdate) {
149 150 151 152 153 154
            if (_canvasSize.getValue() != _canvas->getSize()) {
                _ignoreCanvasSizeUpdate = true;
                _canvas->setSize(_canvasSize.getValue());
                _ignoreCanvasSizeUpdate = false;
            }
        }
schultezub's avatar
schultezub committed
155 156
    }

157 158 159 160 161 162 163
    void AbstractPipeline::onFullscreenChanged(const AbstractProperty * prop)
    {
        if (_canvas) {
            _canvas->toggleFullScreen();
        }
    }

164 165 166 167
    void AbstractPipeline::paint() {
        // render nothing. May be overridden in sub classes.
    }

schultezub's avatar
schultezub committed
168
    const DataContainer& AbstractPipeline::getDataContainer() const {
169
        return *_dataContainer;
schultezub's avatar
schultezub committed
170 171
    }

172
    DataContainer& AbstractPipeline::getDataContainer() {
173
        return *_dataContainer;
174 175
    }

176
    void AbstractPipeline::executeProcessor(AbstractProcessor* processor) {
177
        cgtAssert(processor != 0, "Processor must not be 0.");
178

179
        // execute processor if needed
180
        if (processor->getEnabled() && !processor->isLocked()) {
181
            if (! processor->isValid()) {
182 183 184
                tbb::tick_count startTime;
                if (processor->getClockExecutionTime())
                    startTime = tbb::tick_count::now();
185 186

                try {
187
                    processor->process(*_dataContainer);
188 189 190 191 192 193 194 195 196
                }
                catch (std::exception& e) {
                    LERROR("Caught unhandled exception while executing processor " << processor->getName() << ": " << e.what());
                }
                catch (...) {
                    LERROR("Caught unhandled exception while executing processor " << processor->getName() << ": unknown exception");
                }

                if (processor->getClockExecutionTime()) {
197 198
                    tbb::tick_count endTime = tbb::tick_count::now();
                    LINFO("Executed processor " << processor->getName() << " duration: " << (endTime - startTime).seconds());
199
                }
200
            }
201
        }
202 203
    }

204 205 206 207
    void AbstractPipeline::executeProcessorAndCheckOpenGLState(AbstractProcessor* processor) {
        AbstractPipeline::executeProcessor(processor);

#ifdef CAMPVIS_DEBUG
208 209
        cgtAssert(cgt::getGlBool(GL_DEPTH_TEST) == false, "Invalid OpenGL state after processor execution, GL_DEPTH_TEST != false.");
        cgtAssert(cgt::getGlBool(GL_SCISSOR_TEST) == false, "Invalid OpenGL state after processor execution, GL_SCISSOR_TEST != false.");
210

211 212
        cgtAssert(cgt::getGlInt(GL_CULL_FACE_MODE) == GL_BACK, "Invalid OpenGL state after processor execution, GL_CULL_FACE_MODE != GL_BACk.");
        cgtAssert(cgt::getGlInt(GL_DEPTH_FUNC) == GL_LESS, "Invalid OpenGL state after processor execution, GL_DEPTH_FUNC != GL_LESS.");
213

214
        cgtAssert(cgt::getGlFloat(GL_DEPTH_CLEAR_VALUE) == 1.f, "Invalid OpenGL state after processor execution, GL_DEPTH_CLEAR_VALUE != 1.f.");
215

216 217 218 219
        cgtAssert(cgt::getGlFloat(GL_RED_SCALE) == 1.f, "Invalid OpenGL state after processor execution, GL_RED_SCALE != 1.f.");
        cgtAssert(cgt::getGlFloat(GL_GREEN_SCALE) == 1.f, "Invalid OpenGL state after processor execution, GL_GREEN_SCALE != 1.f.");
        cgtAssert(cgt::getGlFloat(GL_BLUE_SCALE) == 1.f, "Invalid OpenGL state after processor execution, GL_BLUE_SCALE != 1.f.");
        cgtAssert(cgt::getGlFloat(GL_ALPHA_SCALE) == 1.f, "Invalid OpenGL state after processor execution, GL_ALPHA_SCALE != 1.f.");
220

221 222 223 224
        cgtAssert(cgt::getGlFloat(GL_RED_BIAS) == 0.f, "Invalid OpenGL state after processor execution, GL_RED_BIAS != 0.f.");
        cgtAssert(cgt::getGlFloat(GL_GREEN_BIAS) == 0.f, "Invalid OpenGL state after processor execution, GL_GREEN_BIAS != 0.f.");
        cgtAssert(cgt::getGlFloat(GL_BLUE_BIAS) == 0.f, "Invalid OpenGL state after processor execution, GL_BLUE_BIAS != 0.f.");
        cgtAssert(cgt::getGlFloat(GL_ALPHA_BIAS) == 0.f, "Invalid OpenGL state after processor execution, GL_ALPHA_BIAS != 0.f.");
225 226 227
#endif
    }

228 229 230 231
    const std::vector<AbstractProcessor*>& AbstractPipeline::getProcessors() const {
        return _processors;
    }

232 233 234 235 236 237
    bool AbstractPipeline::getEnabled() const {
        return _enabled;
    }

    void AbstractPipeline::setEnabled(bool enabled) {
        _enabled = enabled;
238
        setPipelineDirty();
239 240
    }

241 242
    void AbstractPipeline::onEvent(cgt::Event* e) {
        // copy and paste from cgt::EventHandler::onEvent() but without deleting e
243
        for (size_t i = 0 ; i < listeners_.size() ; ++i) {
Christian Schulte zu Berge's avatar
Christian Schulte zu Berge committed
244 245
            // don't forward this event to ourselves - otherwise we'll end up with an endless loop.
            if (listeners_[i] == this) {
246
                cgt::EventListener::onEvent(e);
Christian Schulte zu Berge's avatar
Christian Schulte zu Berge committed
247
            }
248
            // check if current listener listens to the eventType of e
Christian Schulte zu Berge's avatar
Christian Schulte zu Berge committed
249
            else if (listeners_[i]->getEventTypes() & e->getEventType() ){
250 251
                listeners_[i]->onEvent(e);
            }
Christian Schulte zu Berge's avatar
Christian Schulte zu Berge committed
252 253 254

            if (e->isAccepted())
                break;
255 256 257
        }
    }

258
    void AbstractPipeline::setCanvas(cgt::GLCanvas* canvas) {
259 260 261
        if (_canvas != nullptr)
            _canvas->setPainter(nullptr);

262
        _canvas = canvas;
263 264 265

        if (_canvas != nullptr)
            _canvas->setPainter(_painter.get());
266 267
    }

268
    void AbstractPipeline::setRenderTargetSize(const cgt::ivec2& size) {
269 270 271 272 273
        if (_canvasSize.getValue() != size && !_ignoreCanvasSizeUpdate) {
            _canvasSize.setValue(size);
        }
    }

274
    const cgt::ivec2& AbstractPipeline::getRenderTargetSize() const {
275 276 277 278 279 280 281
        return _canvasSize.getValue();
    }

    const std::string& AbstractPipeline::getRenderTargetID() const {
        return _renderTargetID.getValue();
    }

282
    void AbstractPipeline::addProcessor(AbstractProcessor* processor) {
283
        cgtAssert(processor != 0, "Processor must not be 0.")
284 285
        _processors.push_back(processor);
    }
286

287 288
    void AbstractPipeline::setPipelineDirty() {
        _pipelineDirty = true;
289

290 291
        if (_enabled)
            _evaluationCondition.notify_all();
292
    }
293 294 295 296 297 298 299 300 301 302

    AbstractProcessor* AbstractPipeline::getProcessor(const std::string& name) const {
        for (auto it = _processors.begin(); it != _processors.end(); ++it) {
            if ((*it)->getName() == name)
                return *it;
        }

        return nullptr;
    }

303 304
    AbstractProcessor* AbstractPipeline::getProcessor(size_t index) const {
        if (index >= _processors.size())
305 306 307 308
            return nullptr;
        return _processors[index];
    }

309 310 311 312
    void AbstractPipeline::onDataContainerDataAdded(std::string name, DataHandle dh) {
        if (name == _renderTargetID.getValue())
            setPipelineDirty();
    }
313 314
    void AbstractPipeline::forceExecuteProcessor(AbstractProcessor* processor) {
        bool enabledState = processor->getEnabled();
315
        
316 317 318 319 320 321
        processor->setEnabled(true);
        processor->invalidate(AbstractProcessor::INVALID_RESULT);
        executeProcessor(processor);

        processor->setEnabled(enabledState);
    }
322 323 324 325 326 327

    const std::unique_ptr<PipelinePainter>& AbstractPipeline::getPipelinePainter() const {
        return _painter;
    }


328
}