function FrameSequentialStereoTest(screenid)
% FrameSequentialStereoTest(screenid)
%
% Tests presentation order and timing of stimulus onset in frame sequential
% stereo mode. This is a perceptual test.
%
% The test will run on the screen with the highest number by default, but
% you can pass a 'screenid' to it, if you want.
%
% After startup, the display will show a mostly constant yellow, red or
% green display. Depending on what you see, it tells you how your graphics
% hardware syncs buffer onset:
%
% A) If you see a constant yellow screen, then your hardware always makes sure
% that a full stereo cycle is presented before executing a Screen('flip')
% command, however its not defined if onset of a new stimulus will happen
% with the left buffer first or with the right buffer. You'd need
% measurement equipment to verify which is the startbuffer. The granularity
% of buffer swaps will be reduced to the duration of two video refresh
% intervals, as indicated by the 'ifi' number printed to the Matlab window.
%
% B) If you see either a constant green or a constant red at each run of the
% script (always red or always green, never anything else), then your
% hardware will sync bufferswaps always to the onset of the left stereo
% buffer (if you see red) or to the right buffer (if you see green).
%
% C) If you see either a constant green or a constant red during one run of the
% script, but you observe different colors at repeated runs of the script,
% or a slow switching between red and green, then that means that your
% hardware doesn't care about syncing bufferswaps to a fixed buffer,
% instead it just swaps at the next VBL, so either the left- or the right-
% stereo buffer of a new stimulus will show first. The maximum flip rate is
% equal to the monitor refresh rate.
%
% In case C) you are out of luck if you use Microsoft Windows. If you use
% Linux, then contact the forum with a feature request, we may implement a
% solution for you. If you run MacOS/X, you can 'force' the graphics
% hardware to always synchronize stimulus onset (flip) to either the left-
% or the right buffers display cycle, and you can query which buffer was
% displayed first after flip, left- or right. However this is a software
% trick which needs calibration. To test if the trick works on your setup,
% do the following:
%
% 1. Wait until color of the display settles to either red or green.
% 2. If its green, press the 'g' key, if its red, press the 'r' key.
% 3. After a short period, the display should settle to a nice green,
% indicating that the trick works, and PTB should write 'GREEN' to the
% Matlab window.
% 4. If the display doesn't stabilize to green, but at least the output of
% the Matlab window corresponds with your percept (GREEN for green, RED for
% red) then that means that your system has very noisy timing.

% History:
% 08/14/07 Written (MK).
% 02/09/16 Updated slightly. OSX support more broken thanks to Apple,
%          Linux support fully available. (MK)

% Running on PTB-3?
AssertOpenGL;

% Same keymappings for all platforms:
KbName('UnifyKeyNames');

redfield = -1;

if nargin < 1
    screenid = [];
end

if isempty(screenid)
    screenid = max(Screen('Screens'));
end

if ~IsLinux
    fprintf('Caution: While the perceptual test in this script will still work (perceptually),\n');
    fprintf('query of the stereobuffer presentation with which flip was synchronized and control\n');
    fprintf('of target stereobuffer to which flip should synchronize, will not work on your operating\n');
    fprintf('system. This feature is only available on GNU/Linux. OSX support got destroyed by Apple.\n');
    fprintf('No support for MS-Windows is possible, due to limitations of that OS.\n\n');
end

% Open double-buffered frame-sequential stereo window on display
% 'screenid', background clear color is black (==0):
win = Screen('OpenWindow', screenid, 0, [], [], [], 1);
ifi = Screen('GetFlipInterval', win)

% Wait until all keys are released:
KbReleaseWait;
count = 0;
delta=[];

% Initialize target field to zero. This is purely random coice and will get
% properly set, once we know the real assignment of buffers to fields.
targetfield = -1;

% Run test loop until keypress:
while 1
    % Count iterations:
    count = count + 1;
    % Show both stereo buffers in black:
    Screen('SelectStereoDrawbuffer', win, 0, -1);
    Screen('FillRect', win, 0);
    Screen('SelectStereoDrawbuffer', win, 1);
    Screen('FillRect', win, 0);
    
    % Flip at earliest point in time:
    t1 = Screen('Flip', win);
    
    % Show left stereo buffer in red:
    Screen('SelectStereoDrawbuffer', win, 0, targetfield);
    Screen('FillRect', win, [255 0 0]);
    % Show right stereo buffer in green:
    Screen('SelectStereoDrawbuffer', win, 1);
    Screen('FillRect', win, [0 255 0]);
    
    % Flip at earliest point in time:
    t2 = Screen('Flip', win);
    
    % Query VBL count of the video frame corresponding to last flip:
    winfo = Screen('GetWindowInfo', win);
    fieldid = winfo.VBLCount;
    if redfield~=-1
        if mod(fieldid, 2) == redfield
            fprintf('RED\n');
        else
            fprintf('GREEN\n');
        end
        
        % Select target start field for flips to be a green frame. If
        % everything works, then the user should only see green after
        % calibration:
        targetfield = 1-redfield;
    else
        fprintf('UNKNOWN: Press g if screen is green, r if screen is red.\n');
    end
    
    delta(count) = t2 - t1;
    
    [down secs keycode] = KbCheck;
    if down
        if keycode(KbName('ESCAPE'))
            break;
        end
        
        if keycode(KbName('r'))
            redfield = mod(fieldid, 2);
        end
        
        if keycode(KbName('g'))
            redfield = mod(fieldid+1, 2);
        end

        if keycode(KbName('x'))
            KbReleaseWait;
            KbWait;
        end
    end
end

% Close display:
Screen('CloseAll');

med = median(delta)
avg = mean(delta)

% Done.
return;
