function FloatTextureDemo(singlefbo, trials)

if nargin < 1
    singlefbo=1;
end;

if nargin < 2
    trials = 1;
end;

% Is the script running in OpenGL Psychtoolbox?
AssertOpenGL;

% Find the screen to use for display:
screenid=max(Screen('Screens'));

% Setup Psychtoolbox for OpenGL 3D rendering support and initialize the
% mogl OpenGL for Matlab wrapper:
InitializeMatlabOpenGL(1);

% Open a double-buffered full-screen window on the main displays screen.
[win , winRect] = Screen('OpenWindow', screenid);

% Read test input image...
impath = [PsychtoolboxRoot '/PsychDemos/konijntjes1024x768.jpg']
%impath = [PsychtoolboxRoot '/PsychDemos/OpenGL4MatlabDemos/earth_512by256.jpg']
inputimage = imread(impath);
% ...convert into grayscale image...
inputimage = rgb2gray(inputimage);
% inputimage = inputimage(1:256,1:256);
% Pad it to be a square, power-of-two image:
msize = pow2(ceil(log2(max(size(inputimage)))))
tmpimage = zeros(msize, msize);
tmpimage(1:size(inputimage,1), 1:size(inputimage,2)) = inputimage(:,:);
inputimage = tmpimage;

% ...and convert it to texture:
inputtex = Screen('MakeTexture', win, inputimage);

% Retrieve an OpenGL handle to it:
texin = Screen('GetOpenGLTexture', win, inputtex);

% Setup the OpenGL rendering context of the onscreen window for use by
% OpenGL wrapper. After this command, all following OpenGL commands will
% draw into the onscreen window 'win':
Screen('BeginOpenGL', win);

% Use 
if glGetIntegerv(GL.MAX_COLOR_ATTACHMENTS_EXT)<2 || singlefbo==0
    singlefbo=0;
else
    singlefbo=1;
end;

% Create framebuffer objects and color buffer textures:
if singlefbo==0
    % Hw only supports one color attachment per FBO. Need to create two
    % FBOs for pingpong:
    [fbos(1), tex(1)]=moglCreateFBO(msize, msize);
    [fbos(2), tex(2)]=moglCreateFBO(msize, msize);
else
    % We use one FBO with two color attachments:
    [fbos(1), tex ]=moglCreateFBO(msize, msize, 2);
    % Set fbos(2) = 0 to signal not to use fbo(2).
    fbos(2)=0;
end;

% Load our bias and rescale shader:
glslnormalizer = LoadGLSLProgramFromFiles('ScaleAndBiasShader');
prebias = glGetUniformLocation(glslnormalizer, 'prescaleoffset');
postbias = glGetUniformLocation(glslnormalizer, 'postscaleoffset');
scalefactor = glGetUniformLocation(glslnormalizer, 'scalefactor');

% Activate it for following blit op:
glUseProgram(glslnormalizer);

% Set no bias to be applied:
glUniform1f(prebias, 0.0);
glUniform1f(postbias, 0.0);

% Multiply all luminance values by 255, so they are in usual range 0-255
% instead of 0-1:
glUniform1f(scalefactor, 255.0);

% Bind FBO 1, colorbuffer 1:
moglChooseFBO(fbos(1), 1);

% Blit input image into it, scaling it from 0-1 to 0-255:
moglBlitTexture(texin);

% Disable shader:
glUseProgram(0);

% Read it back (only the RED channel, it is a grayscale image, so
% red, green and blue contain the same content. We read it back to make
% sure we can compare Matlabs results to the GPU results:
inputimage = glReadPixels(0, 0, msize, msize, GL_RED, GL_FLOAT);

% Unbind FBO, reset to normal framebuffer:
moglChooseFBO(0);

% Perform reduce operation to compute texture properties:
[minv, maxv, meanv] = moglComputeMinMaxMeanOfTexture(moglGetTexForFBO(fbos(1), 1), fbos(1), fbos(2), 1);
glFinish;
tic;
for c=1:trials
    % We use the texture of fbo(1) as input image, as we know that fbo-1
    % will not be used as drawing target in first iteration. We provide
    % fbo(1) and fbo(2) as ping-pong buffers for iterative reduce
    % operation:
    [dminv, dmaxv, dmeanv] = moglComputeMinMaxMeanOfTexture(moglGetTexForFBO(fbos(1), 1), fbos(1), fbos(2), 1);
end;
durationgpu = toc / trials;

minc=min(min(inputimage));
maxc=max(max(inputimage));
meanc=mean(mean(inputimage));

tic;
minc=min(min(inputimage));
maxc=max(max(inputimage));
meanc=mean(mean(inputimage));
durationcpu = toc;

fprintf('Minimum   CPU = %f  , OpenGL = %f\n', minc, minv);
fprintf('Maximum   CPU = %f  , OpenGL = %f\n', maxc, maxv);
fprintf('Mean      CPU = %f  , OpenGL = %f\n', meanc, meanv);
fprintf('Time/pass CPU = %f ms, OpenGL = %f ms\n', durationcpu * 1000, durationgpu * 1000);

% Disable our FBO's:
moglChooseFBO(0);

% Finish OpenGL rendering into PTB window and check for OpenGL errors.
Screen('EndOpenGL', win);

% Render something into visible framebuffer just to check for
% interference...
glClearColor(1,1,0,0);
glClear(GL.COLOR_BUFFER_BIT);
glColor4f(1,0,0,1);
glBegin(GL.TRIANGLES)
glVertex2d(0,0);
glVertex2d(256,0);
glVertex2d(128,256);
glEnd;
% Show rendered image at next vertical retrace:
Screen('Flip', win);

Screen('BeginOpenGL', win);

% Ok draw our image into FBO again, this time normalizing it, so that the
% range [min ; max] maps to interval [0 ; 1]:

% Draw into FBO 1:
moglChooseFBO(fbos(1), 1);

% Activate remap shader for following blit op:
glUseProgram(glslnormalizer);

minv = minv / 255;
maxv = maxv / 255;
sf = 1.0 / (maxv - minv);

% Set bias to be applied: This maps the minimum value to zero:
glUniform1f(prebias, -minv);
% No post-scale bias:
glUniform1f(postbias, 0.0);
% Scale factor to spread out everything into range 0.0 - 1.0:
glUniform1f(scalefactor, sf);

% Blit input image into it, remapping/normalizing it to range 0.0 - 1.0:
moglBlitTexture(texin);

% Disable shader:
glUseProgram(0);

% Read blitted textures back from FBOs:
% This shows the normalized 0-1 edge-map:
moglChooseFBO(fbos(1), 1);
img = glReadPixels(0, 0, msize, msize, GL_RGB, GL_FLOAT);

if singlefbo==0
    % Dual FBO-case:
    moglChooseFBO(fbos(2), 1);
else
    % Dual color buffer on single FBO case:
    moglChooseFBO(fbos(1), 2);
end;

img2 = glReadPixels(0, 0, msize, msize, GL_RGB, GL_FLOAT);

% Unbind FBO, reset to normal framebuffer:
moglChooseFBO(0);

% Delete all FBO's:
for i=1:length(fbos)
    moglDeleteFBO(fbos(i));
end;

% Shut down OpenGL rendering:
Screen('EndOpenGL', win);

% Close onscreen window and release all other ressources:
sca;

imshow(img);
figure
imshow(img2, [0 255]);
figure

imshow(inputimage, [0 255]);

% Well done!
return
