glreduction.cpp 9.52 KB
Newer Older
1
2
3
4
// ================================================================================================
// 
// This file is part of the CAMPVis Software Framework.
// 
5
// If not explicitly stated otherwise: Copyright (C) 2012-2013, all rights reserved,
6
7
8
9
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
//      Chair for Computer Aided Medical Procedures
//      Technische Universität München
//      Boltzmannstr. 3, 85748 Garching b. München, Germany
10
// 
11
12
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
// 
13
14
15
16
// 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
17
// 
18
19
20
21
// 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.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 
// ================================================================================================

#include "glreduction.h"

#include "tgt/logmanager.h"
#include "tgt/framebufferobject.h"
#include "tgt/shadermanager.h"
#include "tgt/texture.h"
#include "tgt/textureunit.h"

#include "core/datastructures/facegeometry.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/tools/quadrenderer.h"

#include <algorithm>

#define DIV_CEIL(x,y) ((x) > 0) ? (1 + ((x) - 1)/(y)) : ((x) / (y))

namespace campvis {

    const std::string GlReduction::loggerCat_ = "CAMPVis.modules.registration.GlReduction";

46
    GlReduction::GlReduction(ReductionOperator reductionOperator, bool isForTesting)
47
        : _reductionOperator(reductionOperator)
48
        , _shader1d(0)
49
50
        , _shader2d(0)
        , _shader3d(0)
51
52
        , _fbo(0)
    {
53
54
55
56
57
58
59
60
61
62
63
        //TODO: discuss details, and generalize this
        if(!isForTesting) {
            _shader1d = ShdrMgr.load("core/glsl/passthrough.vert", "core/glsl/tools/glreduction.frag", generateGlslHeader(_reductionOperator) + "#define REDUCTION_1D\n");
            _shader2d = ShdrMgr.load("core/glsl/passthrough.vert", "core/glsl/tools/glreduction.frag", generateGlslHeader(_reductionOperator) + "#define REDUCTION_2D\n");
            _shader3d = ShdrMgr.load("core/glsl/passthrough.vert", "core/glsl/tools/glreduction.frag", generateGlslHeader(_reductionOperator) + "#define REDUCTION_3D\n");
        }
        else {
            _shader1d = ShdrMgr.load("../src/core/glsl/passthrough.vert", "../src/core/glsl/tools/glreduction.frag", generateGlslHeader(_reductionOperator) + "#define REDUCTION_1D\n");
            _shader2d = ShdrMgr.load("../src/core/glsl/passthrough.vert", "../src/core/glsl/tools/glreduction.frag", generateGlslHeader(_reductionOperator) + "#define REDUCTION_2D\n");
            _shader3d = ShdrMgr.load("../src/core/glsl/passthrough.vert", "../src/core/glsl/tools/glreduction.frag", generateGlslHeader(_reductionOperator) + "#define REDUCTION_3D\n");
        }
64
        if (_shader1d == 0 || _shader2d == 0 || _shader3d == 0) {
65
66
67
68
            LERROR("Could not load Shader for OpenGL reduction. Reduction will not work!");
            return;
        }

69
70
        _shader1d->setAttributeLocation(0, "in_Position");
        _shader1d->setAttributeLocation(1, "in_TexCoord");
71
72
73
74
        _shader2d->setAttributeLocation(0, "in_Position");
        _shader2d->setAttributeLocation(1, "in_TexCoord");
        _shader3d->setAttributeLocation(0, "in_Position");
        _shader3d->setAttributeLocation(1, "in_TexCoord");
75
76
77
    }

    GlReduction::~GlReduction() {
78
        ShdrMgr.dispose(_shader1d);
79
80
        ShdrMgr.dispose(_shader2d);
        ShdrMgr.dispose(_shader3d);
81
82
    }

83
    std::vector<float> GlReduction::reduce(const ImageData* image) {
84
        tgtAssert(image != 0, "Image must not be 0!");
85
        if (_shader1d == 0 || _shader2d == 0 || _shader3d == 0) {
86
            LERROR("Could not load Shader for OpenGL reduction. Reduction will not work!");
87
            return std::vector<float>();
88
89
90
        }
        if (image == 0) {
            LERROR("Empty image received - nothing to reduce!");
91
            return std::vector<float>();
92
93
94
95
96
        }

        const ImageRepresentationGL* repGl = image->getRepresentation<ImageRepresentationGL>();
        if (repGl == 0) {
            LERROR("Could not convert input image to OpenGL texture - no reduction possible!");
97
            return std::vector<float>();
98
99
        }

100
101
102
        return reduce(repGl->getTexture());
    }
    
103
104
105
    std::vector<float> GlReduction::reduce(const tgt::Texture* texture) {
        std::vector<float> toReturn;

106
        tgtAssert(texture != 0, "Image must not be 0!");
107
        if (_shader1d == 0 || _shader2d == 0 || _shader3d == 0) {
108
            LERROR("Could not load Shader for OpenGL reduction. Reduction will not work!");
109
            return toReturn;
110
111
112
        }
        if (texture == 0) {
            LERROR("Empty texture received - nothing to reduce!");
113
            return toReturn;
114
        }
115

116
        const tgt::ivec3& size = texture->getDimensions();
117
        tgt::ivec2 texSize = size.xy();
118
119
120
121
122
123

        // Set OpenGL pixel alignment to 1 to avoid problems with NPOT textures
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

        // get a free texture unit
        tgt::TextureUnit inputUnit;
124
        inputUnit.activate();
125
126

        // create temporary textures
127
        tgt::Texture* tempTextures[2];
128
        for (size_t i = 0; i < 2; ++i) {
129
            tempTextures[i] = new tgt::Texture(0, tgt::ivec3(texSize, 1), GL_RGBA, GL_RGBA32F, GL_FLOAT, tgt::Texture::NEAREST);
130
            tempTextures[i]->uploadTexture();
131
            tempTextures[i]->setWrapping(tgt::Texture::CLAMP_TO_EDGE);
132
        }
133
134
135

        const tgt::Texture* inputTex = texture;
        tgt::Texture* outputTex = tempTextures[1];
136
137
138
139
140
141

        // create and initialize FBO
        _fbo = new tgt::FramebufferObject();
        _fbo->activate();
        LGL_ERROR;

142
143
144
145
        // perform 3D reduction if needed
        if (texture->getDimensions().z > 1) {
            _shader3d->activate();
            _fbo->attachTexture(outputTex);
146

147
148
149
150
151
152
153
            inputTex->bind();
            _shader3d->setUniform("_texture", inputUnit.getUnitNumber());
            _shader3d->setUniform("_textureSize", size);

            glViewport(0, 0, texSize.x, texSize.y);
            QuadRdr.renderQuad();
            _shader3d->deactivate();
154

155
156
157
158
            inputTex = outputTex;
            outputTex = tempTextures[0];
            LGL_ERROR;
        }
159

160
161
162
163
        // perform 2D reduction if needed
        if (texture->getDimensions().y > 1) {
            _shader2d->activate();
            _fbo->attachTexture(outputTex);
164

165
166
167
168
169
            inputTex->bind();
            _shader2d->setUniform("_texture", inputUnit.getUnitNumber());
            _shader2d->setUniform("_textureSize", size.xy());

            glViewport(0, 0, texSize.x, 1);
170
            QuadRdr.renderQuad();
171
            _shader2d->deactivate();
172

173
174
175
            inputTex = outputTex;
            outputTex = (outputTex == tempTextures[1]) ? tempTextures[0] : tempTextures[1];
            LGL_ERROR;
176
177
        }

178
179
180
181
182
183
184
185
        // finally, perform 1D reduction if needed
        {
            _shader1d->activate();
            _fbo->attachTexture(outputTex);

            inputTex->bind();
            _shader1d->setUniform("_texture", inputUnit.getUnitNumber());
            _shader1d->setUniform("_textureSize", size.xy());
186

187
188
189
190
191
            glViewport(0, 0, 1, 1);
            QuadRdr.renderQuad();
            _shader1d->deactivate();
            LGL_ERROR;
        }
192
193

        // read back stuff
194
195
196
        GLenum readBackFormat = outputTex->getFormat();
        size_t channels = outputTex->getNumChannels();
        toReturn.resize(channels);
197
        glReadBuffer(GL_COLOR_ATTACHMENT0);
198
        glReadPixels(0, 0, 1, 1, readBackFormat, GL_FLOAT, &toReturn.front());
199
200
201
202
203
204
205
206
        LGL_ERROR;

        // clean up...
        _fbo->detachAll();
        _fbo->deactivate();
        delete _fbo;
        _fbo = 0;

207
208
        delete tempTextures[0];
        delete tempTextures[1];
209
210
        LGL_ERROR;

211
        return toReturn;
212
213
214
    }


215
216
    std::string GlReduction::generateGlslHeader(ReductionOperator reductionOperator) {
        switch (reductionOperator) {
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
            case MIN:
                return 
                    "#define REDUCTION_OP_2(a, b) min(a, b)\n"
                    "#define REDUCTION_OP_4(a, b, c, d) min(a, min(b, min(c, d)))\n";
                break;
            case MAX:
                return 
                    "#define REDUCTION_OP_2(a, b) max(a, b)\n"
                    "#define REDUCTION_OP_4(a, b, c, d) max(a, max(b, max(c, d)))\n";
                break;
            case PLUS:
                return 
                    "#define REDUCTION_OP_2(a, b) a+b\n"
                    "#define REDUCTION_OP_4(a, b, c, d) a+b+c+d\n";
                break;
            case MULTIPLICATION:
                return 
                    "#define REDUCTION_OP_2(a, b) a*b\n"
                    "#define REDUCTION_OP_4(a, b, c, d) a*b*c*d\n";
                break;
            case MIN_MAX_DEPTH_ONLY:
                return 
                    "#define REDUCTION_OP_2(a, b) vec4(min(a.r, b.r), max(a.g, b.g), 0.0, 0.0)\n"
                    "#define REDUCTION_OP_4(a, b, c, d) vec4(min(a.r, min(b.r, min(c.r, d.r))), max(a.g, max(b.g, max(c.g, d.g))), 0.0, 0.0)\n";
                break;
            default:
                tgtAssert(false, "Should not reach this, wrong enum value?");
                return "";
                break;
246
247
248
        }
    }

249
}