This file is indexed.

/usr/share/psychtoolbox-3/PsychGLImageProcessing/CreateResolutionPyramid.m is in psychtoolbox-3-common 3.0.11.20131230.dfsg1-1build1.

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
213
214
215
function CreateResolutionPyramid(tex, glsl, usebilinear)
% Build a mip-map image resolution pyramid for given texture.
%
% CreateResolutionPyramid(tex [, glsl=0][, usebilinear=0])
%
% 'tex' must be the Screen() texture or offscreen window handle of a
% texture or offscreen window of type GL_TEXTURE_2D, ie., created with
% 'specialFlags' setting 1. The function will create a OpenGL mip-map
% resolution pyramid by successive downsampling of 'tex' image content down
% to a image of 1x1 pixels. If 'glsl' is provided as handle to a shader, it
% will use that shader to do the downsampling, otherwise it will use
% bilinear filtering for successive pyramid levels. If 'usebilinear' is set
% to 1 it will feed the shader with linear interpolated samples, otherwise
% with nearest neighbour samples.
%
% You will likely also want to set 'specialFlags' flag 8 or 16 to prevent
% Screen('DrawTexture') from overwriting the image pyramid with its own
% auto-generated one.
%
% This needs a modern GLSL shading capable graphics card to work.
%

% History:
% 27.08.2012  mk   Written.
%

% Needed for GL constant definitions:
global GL;

% Make sure MOGL is initialized:
if isempty(GL)
    InitializeMatlabOpenGL([],[],1);
end

if nargin < 1 || isempty(tex)
    error('Must provide a valid Screen() texture or offscreen window handle for building of resolution pyramid!');
end

if nargin < 2 || isempty(glsl)
    glsl = 0;
end

if nargin < 3 || isempty(usebilinear)
    usebilinear = 0;
end

% Only supported for offscreen targets, not onscreen windows, proxies etc.:
if Screen('WindowKind', tex) ~= -1
    error('Tried to built a resolution image pyramid for something else than a texture or offscreen window! Unsupported.');
end

% This, as a well defined side effect, will bind the tex'tures associated
% FBO, or create one if it doesn't have one yet, as well as normalize the
% textures format and orientation, just as we need it:
Screen('GetWindowInfo', tex);

% Get width and height:
[w, h] = Screen('WindowSize', tex);

% Get low-level texture handle and type:
[gltexid, gltextarget] = Screen('GetOpenGLTexture', tex, tex);

% Make sure it is a mip-map capable type:
if gltextarget ~= GL.TEXTURE_2D
    error('Tried to built a resolution image pyramid for something else than a GL_TEXTURE_2D texture! Unsupported.');
end

% Time for a state backup:
glPushAttrib(GL.ALL_ATTRIB_BITS);

% Ok, the currently bound FBO is the FBO to use for drawing into this
% texture. And we got the gltexid of the corresponding texture.
% We also know that all texture parameters are set in a way to make it
% available as a rendertarget, e.g., the texture minification/magnification
% filters, wrap modes etc. are set to safe values, e.g., nearest neighbour
% sampling, clamp to edge etc.

% Bind the texture:
glBindTexture(gltextarget, gltexid);

% Enable sampling:
glDisable(GL.TEXTURE_RECTANGLE_EXT);
glEnable(gltextarget);

% Compute to what miplevel we need to downsample to cover all bases:
maxlod = floor(log2(max(w, h)));

% Query size of mip-level 'maxlod':
tw = glGetTexLevelParameteriv(gltextarget, maxlod, GL.TEXTURE_WIDTH);
th = glGetTexLevelParameteriv(gltextarget, maxlod, GL.TEXTURE_HEIGHT);

% If no such mip-level exists?
if tw == 0 || th == 0
    % No such mip-level: Generate initial mip-chain for this texture. We
    % allocate mip-levels of proper format and size, but empty, ie.,
    % without actually computing any content here:
    internalFormat = glGetTexLevelParameteriv(gltextarget, 0, GL.TEXTURE_INTERNAL_FORMAT);

    for miplevel = 1:maxlod
        % Need to case tw, th to double(), use max() operators and whatnot
        % to get proper size specs -- Matlab arithmetic on the returned
        % int32's from query behaves rather strange otherwise:
        tw = double(glGetTexLevelParameteriv(gltextarget, miplevel - 1, GL.TEXTURE_WIDTH));
        th = double(glGetTexLevelParameteriv(gltextarget, miplevel - 1, GL.TEXTURE_HEIGHT));
        glTexImage2D(gltextarget, miplevel, internalFormat, max(floor(tw/2), 1), max(floor(th/2), 1), 0, GL.RGBA, GL.UNSIGNED_BYTE, 0);
    end
end

% Bind downsampling shader and set it up to read from texture unit 0:
glUseProgram(glsl);

% If we've actually bound the fixed-function pipeline, we skip this step:
if glsl ~= 0
    glUniform1i(glGetUniformLocation(glsl, 'Image'), 0);
    
    % Query locations of uniforms for passing src / dst dimensions:
    srcSize = glGetUniformLocation(glsl, 'srcSize');
    dstSize = glGetUniformLocation(glsl, 'dstSize');
end

% Just to be extra safe:
glTexParameteri(gltextarget, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE);
glTexParameteri(gltextarget, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE);

if glsl ~= 0 && ~usebilinear
    % Use nearest neighbour sampling for real downsampling shaders, so they
    % have full control over actual sampling:
    glTexParameteri(gltextarget, GL.TEXTURE_MIN_FILTER, GL.NEAREST);
    glTexParameteri(gltextarget, GL.TEXTURE_MAG_FILTER, GL.NEAREST);
else
    % For fixed function, use bilinear filtering. This should pretty much
    % emulate a 2x2 texels box-filter:
    glTexParameteri(gltextarget, GL.TEXTURE_MIN_FILTER, GL.LINEAR);
    glTexParameteri(gltextarget, GL.TEXTURE_MAG_FILTER, GL.LINEAR);
end

% Base level 0 is always enabled, as we never write to it:
glTexParameteri(gltextarget, GL.TEXTURE_BASE_LEVEL, 0);

% Iterate over all mip-levels 'miplevel' from 1 to maxlod, and source each
% 'miplevel-1' to compute 'miplevel':
for miplevel = 1:maxlod
    % Query size of target mip level:
    tw = glGetTexLevelParameteriv(gltextarget, miplevel, GL.TEXTURE_WIDTH);
    th = glGetTexLevelParameteriv(gltextarget, miplevel, GL.TEXTURE_HEIGHT);

    % If size is smaller than 1 texel in any dimension, exit the downsampling loop:
    if tw < 1 || th < 1
        break;
    end
    
    % Set mip-level upper range limit for sampling from texture from to "miplevel-1":
    glTexParameteri(gltextarget, GL.TEXTURE_MAX_LEVEL, miplevel-1);
    
    % Select the target mip-level for drawing into (== render-to-texture
    % via FBO color attachment) to 'miplevel':
    glFramebufferTexture2DEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT0_EXT, gltextarget, gltexid, miplevel);

    % Setup drawing transforms, projection and viewport:
    glMatrixMode(GL.PROJECTION);
    glLoadIdentity;
    gluOrtho2D(0, tw, 0 , th);
    glMatrixMode(GL.MODELVIEW);
    glLoadIdentity;
    glViewport(0, 0, tw, th);
    
    % Ok, we should be setup properly now. Any shader sampling from the
    % texture can only do nearest neighbour sampling from level
    % 'miplevel-1', and all writes go to 'miplevel'.
    
    % Communicate sizes of source and destination surface to possible
    % shaders:
    if glsl
        glUniform2f(srcSize, glGetTexLevelParameteriv(gltextarget, miplevel-1, GL.TEXTURE_WIDTH), glGetTexLevelParameteriv(gltextarget, miplevel-1, GL.TEXTURE_HEIGHT));
        glUniform2f(dstSize, tw, th);
    end
    
    % Blit a "fullscreen quad" - or more specifically a full-texture quad
    % to drive the downsampling shader:
    glColor4f(1,1,1,1);
    glBegin(GL.QUADS)
    glTexCoord2f(0,0);
    glVertex2f(0,0);
    glTexCoord2f(0,1);
    glVertex2f(0,th);
    glTexCoord2f(1,1);
    glVertex2f(tw,th);
    glTexCoord2f(1,0);
    glVertex2f(tw,0);
    glEnd;
    % Rinse, wash, repeat at next miplevel...
end

% Reset mip-level range to normal:
glTexParameteri(gltextarget, GL.TEXTURE_BASE_LEVEL, 0);
glTexParameteri(gltextarget, GL.TEXTURE_MAX_LEVEL, 1000);
    
% Disable and unbind texture:
glDisable(gltextarget);
glBindTexture(gltextarget, 0);

% Restore framebuffer attachment for texture to render into miplevel zero:
glFramebufferTexture2DEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT0_EXT, gltextarget, gltexid, 0);

% Unbind shader:
glUseProgram(0);

% Final state: Texture unbound from sampler, but bound as current
% framebuffer/rendertarget. Regular PTB code will take care of this.

% Restore pre-op state:
glPopAttrib;

% Done.
return;