This file is indexed.

/usr/share/psychtoolbox-3/PsychOpenGL/PsychGLSLShaders/moglComputeMinMaxMeanOfTexture.m is in psychtoolbox-3-common 3.0.11.20140816.dfsg1-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
function [minv, maxv, meanv] = moglComputeMinMaxMeanOfTexture(texid, pingpongfbo1, pingpongfbo2, fastpath)
% [minv, maxv, meanv] = moglComputeMinMaxMeanOfTexture(texid, pingpongfbo1, pingpongfbo2, fastpath)
%
% This function expects a square RGB texture as input, whose color channels
% contain identical values L=R=G=B where L is a grayscale (luminance) input
% image. It computes and returns its global minimum, maximum and mean luminance
% on the GPU.
%
% The width and height of the texture need to be divisible by two (even numbers).
% It only works on RECTANGLE textures, not on standard power-of-two textures!
% You are not allowed to use an input texture 'texid' that is identical to
% the color buffer texture of the FBO 'pingpongfbo2'!

% Notes:
% FBO ping-ponging takes 13.7 ms on GeForce-7800 for 256 by 256 image.
%
% History:
% 30.5.2006 Written (MK).

% Need handle to GL constant definitions:
global GL;

% We cache our reduction shader for reuse on later invocations:
persistent reduceshader;
if isempty(reduceshader)
    reduceshader = LoadGLSLProgramFromFiles('MinMaxMeanReduceShader');
end;

if nargin < 4
    fastpath = 0;
else
    if isempty(fastpath)
        fastpath = 0;
    end;
end;

if nargin < 2
    error('Need texid of input texture and the fbo-handles of at least the first ping-pong FBO!');
end;

% Query size of input texture:
glBindTexture(GL.TEXTURE_RECTANGLE_EXT, texid);
w = glGetTexLevelParameteriv(GL.TEXTURE_RECTANGLE_EXT, 0, GL.TEXTURE_WIDTH);
h = glGetTexLevelParameteriv(GL.TEXTURE_RECTANGLE_EXT, 0, GL.TEXTURE_HEIGHT);

% We skip all error checking and such if fastpath > 0. This saves about 4
% ms of setup time.
if fastpath == 0
    % Take the slow, but safe route:    
    if ~glIsFramebufferEXT(pingpongfbo1)
        error('Invalid pingpongfbo1 identifier passed. This is not a valid FBO.');
    end;

    if nargin < 3
        pingpongfbo2 = 0;
    end;

    if isempty(pingpongfbo2)
        pingpongfbo2 = 0;
    end;

    if pingpongfbo2 > 0
        % Second bounce buffer provided. Check it.
        if ~glIsFramebufferEXT(pingpongfbo2)
            error('Invalid pingpongfbo2 identifier passed. This is not a valid FBO.');
        end;
        singlefbo = 0;
    else
        % Only one FBO provided, make sure that one has two color attachments:
        glBindFramebufferEXT(GL.FRAMEBUFFER_EXT, pingpongfbo1);
        if glGetFramebufferAttachmentParameterivEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT1_EXT, GL.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT)~=GL.TEXTURE
            error('Only pingpongfbo1 provided, not pingpongfbo2 *and* pingpongfbo1 does not have 2 color buffers. This will not work...');
        end;
        singlefbo = 1;
    end;

    if w~=h || w<2 || mod(w,2)>0
        error('Invalid size of input texture: Needs to be even, width = height and at least 2 pixels wide.');
    end;

    % Query size of FBO's:
    glBindFramebufferEXT(GL.FRAMEBUFFER_EXT, pingpongfbo1);
    fbotexid = glGetFramebufferAttachmentParameterivEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT0_EXT, GL.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT);
    glBindTexture(GL.TEXTURE_RECTANGLE_EXT, fbotexid);
    fw = glGetTexLevelParameteriv(GL.TEXTURE_RECTANGLE_EXT, 0, GL.TEXTURE_WIDTH);
    fh = glGetTexLevelParameteriv(GL.TEXTURE_RECTANGLE_EXT, 0, GL.TEXTURE_HEIGHT);
    glBindTexture(GL.TEXTURE_RECTANGLE_EXT, 0);
    if fw < w/2 || fh < h/2
        error('Pingpong FBO 1 is too small for reduce operation!');
    end;

    % Query size of FBO's:
    if singlefbo == 0
        glBindFramebufferEXT(GL.FRAMEBUFFER_EXT, pingpongfbo2);
        fbotexid = glGetFramebufferAttachmentParameterivEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT0_EXT, GL.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT);
        glBindTexture(GL.TEXTURE_RECTANGLE_EXT, fbotexid);
        fw = glGetTexLevelParameteriv(GL.TEXTURE_RECTANGLE_EXT, 0, GL.TEXTURE_WIDTH);
        fh = glGetTexLevelParameteriv(GL.TEXTURE_RECTANGLE_EXT, 0, GL.TEXTURE_HEIGHT);
        glBindTexture(GL.TEXTURE_RECTANGLE_EXT, 0);
        if fw < w/2 || fh < h/2
            error('Pingpong FBO 2 is too small for reduce operation!');
        end;
    end;

    % Make sure we don't try to read from the pingpongfbo2's texture as input
    % texture - that would cause undefined behaviour.
    if singlefbo == 0
        if texid == moglGetTexForFBO(pingpongfbo2)
            error('Input texture texid is the texture attached to pingpongfbo2! Thats forbidden! Aborted.');
        end;
    else
        if texid == moglGetTexForFBO(pingpongfbo1, 2)
            error('Input texture texid is the texture attached to color buffer 2 of pingpongfbo1! That is forbidden! Aborted.');
        end;
    end;
else
    % Fast path: Minimal setup, no error checks:
    if pingpongfbo2 > 0
        singlefbo = 0;
    else
        singlefbo = 1;
    end;
end;

% Ok we survived error-checking, everything is fine. Do it:
reducestep = 2;
numiters = ceil(log(double(w))/log(reducestep));
currentsize = w;

% On first iteration we operate on the input texture:
inputtex = texid;

% Setup texture mapping:
glDisable(GL.TEXTURE_2D);
glEnable(GL.TEXTURE_RECTANGLE_EXT);

% Make sure we use nearest neighbour sampling:
glTexParameteri(GL.TEXTURE_RECTANGLE_EXT, GL.TEXTURE_MIN_FILTER, GL.NEAREST);
glTexParameteri(GL.TEXTURE_RECTANGLE_EXT, GL.TEXTURE_MAG_FILTER, GL.NEAREST);
% And that we clamp to edge:
glTexParameteri(GL.TEXTURE_RECTANGLE_EXT, GL.TEXTURE_WRAP_S, GL.CLAMP);
glTexParameteri(GL.TEXTURE_RECTANGLE_EXT, GL.TEXTURE_WRAP_T, GL.CLAMP);

% Do a full setup of the initial FBO and colorbuffer before iterating,
% because this is very costly. The iteration loops only do the minimal
% amount of switching via glXXX calls to reduce switch-overhead:
if singlefbo==1
    % One FBO, two buffers:
    moglChooseFBO(pingpongfbo1, 2);
    buffertex(1)=glGetFramebufferAttachmentParameterivEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT0_EXT, GL.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT);
    buffertex(2)=glGetFramebufferAttachmentParameterivEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT1_EXT, GL.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT);
else
    % Two FBO's:
    glBindFramebufferEXT(GL.FRAMEBUFFER_EXT, pingpongfbo1);
    buffertex(1)=glGetFramebufferAttachmentParameterivEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT0_EXT, GL.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT);    
    moglChooseFBO(pingpongfbo2, 1);
    buffertex(2)=glGetFramebufferAttachmentParameterivEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT0_EXT, GL.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT);    
end;

% Activate reduce-shader:
glUseProgram(reduceshader);

% Do numiters pingpong-reduce operations:
bufferid = 0;
for i=1:numiters
    % Compute drawbuffers id and its texturehandle:
    bufferid = 1 - bufferid;
    futuretex = buffertex(bufferid + 1);

    % Bind proper FBO as target for intermediate reduce results:
    if singlefbo == 0
        % Use two FBO's for pingpong:
        if bufferid==0
            glBindFramebufferEXT(GL.FRAMEBUFFER_EXT, pingpongfbo1);
        else
            glBindFramebufferEXT(GL.FRAMEBUFFER_EXT, pingpongfbo2);
        end;
    else
        % Use one dual-buffer FBO for pingpong:
        % We only switch the draw-buffer to keep the overhead as low as
        % possible:
        glDrawBuffer(GL.COLOR_ATTACHMENT0_EXT + bufferid);
    end;
    
    % Perform reduction blit operation to a size of 'currentsize' by 'currentsize':
    currentsize = floor(currentsize / reducestep);

    % Do it: We use fast-blit mode (1) because we did texture setup
    % ourselves:
    moglBlitTexture(inputtex, 0, 0, currentsize, currentsize, 1);

    % Assign source texture for next pass:
    inputtex = futuretex;
end;

% Ok, pixel (0,0) of our currently bound FBO should contain the final
% result. Read it out:
if singlefbo == 0, bufferid = 0; end;
glReadBuffer(GL.COLOR_ATTACHMENT0_EXT + bufferid);
resultpixel = double(glReadPixels(0, 0, 1, 1, GL.RGB, GL.FLOAT));
meanv = resultpixel(1);
maxv  = resultpixel(2);
minv  = resultpixel(3);

% Disable texture mapping...
glDisable(GL.TEXTURE_RECTANGLE_EXT);
glBindTexture(GL.TEXTURE_RECTANGLE_EXT, 0);
% ...disable reduce - shader:
glUseProgram(0);

% Well done!
return;