/usr/share/psychtoolbox-3/PsychTests/GraphicsDisplaySyncAcrossDualHeadsTest.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 | function GraphicsDisplaySyncAcrossDualHeadsTest(screenids, nrtrials, driftsync)
% GraphicsDisplaySyncAcrossDualHeadsTest([screenids] [, nrtrials=6000] [, driftsync=0])
%
% Test synchronizity between the scanout/refresh cycles of two different
% display heads 'screenids(1)' and 'screenids(2)'. If 'screenids' is
% omitted, we test the two heads with maximal id. 'nrtrial' sample passes
% with a sampling interval of roughly 1 msecs are conducted. 'nrtrials'
% defaults to 6000 samples.
%
% Each sample consists of querying the current rasterbeam position and
% timestamp of last VBL interrupt on each display head. At the end, the
% samples of both heads are plotted against each other and compared.
%
% The help text in the Matlab prompt tells you how to interpret the plots.
% History:
% 12/11/07 Written (MK).
AssertOpenGL;
if nargin < 1
screenids = [];
end
if isempty(screenids)
screenids = Screen('Screens');
if length(screenids)<2
% Only single head - Nothing to test?!?
error('Only one display head attached to graphics hardware. How am i supposed to test sync across heads?!?');
end
if length(screenids)>2
% If more than two heads available, choose the two heads with
% maximum id:
screenids = screenids(end-1:end);
end
end
if length(screenids) > 2
error('"screenids" parameter contains indices of more than two screens?!? This is a dual-head sync test!');
end
if nargin < 2
nrtrials = [];
end
if isempty(nrtrials)
nrtrials = 6000;
end
if nargin < 3
driftsync = [];
end
if isempty(driftsync)
driftsync = 0;
end
driftsync = driftsync * 2;
testvblirqs = 1;
% Open windows:
w(1) = Screen('OpenWindow', screenids(1), 0, []);
w(2) = Screen('OpenWindow', screenids(2), 0, []);
if driftsync > 0
WaitSecs(2);
% Query current display settings for 1st display:
oldResolution(1)=Screen('Resolution', screenids(1));
% Switch 1st display to 60 Hz refresh rate:
if oldResolution(1).hz ~=0
Screen('Resolution', screenids(1), oldResolution(1).width, oldResolution(1).height, 60, oldResolution(1).pixelSize, 1);
end
% Query current display settings for 2nd display:
oldResolution(2)=Screen('Resolution', screenids(2));
% Switch 2nd display to 75 Hz refresh rate:
Screen('Resolution', screenids(2), oldResolution(2).width, oldResolution(2).height, 75, oldResolution(2).pixelSize, 1);
WaitSecs(2);
end
% Some beauty...
Screen('Flip', w(1), 0, 2);
Screen('Flip', w(2), 0, 2);
Screen('FillRect', w(1), 255);
Screen('FillRect', w(2), 255);
Screen('Flip', w(1), 0, 2);
Screen('Flip', w(2), 0, 2);
if driftsync > 0
nrtrials = 100000;
end
timinginfo = zeros(2, 2, nrtrials);
syncedattrial = -1;
% Test loop one:
for i=1:nrtrials
% Sample in roughly 1 msec intervals:
WaitSecs(0.001);
% Sample in close sync:
for j=1:2
winfo(j) = Screen('GetWindowInfo', w(j)); %#ok<AGROW>
end
for j=1:2
timinginfo(1, j,i) = winfo(j).Beamposition;
timinginfo(2, j,i) = winfo(j).LastVBLTime;
end
if driftsync > 1
if abs(winfo(1).LastVBLTime - winfo(2).LastVBLTime) < 0.0005
% Switch display 2 also to 60 Hz refresh:
Screen('Resolution', screenids(2), oldResolution(2).width, oldResolution(2).height, 60, oldResolution(2).pixelSize, 1);
driftsync = 1;
syncedattrial = i %#ok<NOPRT>
drawnow;
Beeper;
end
end
if (driftsync == 1) && (i > syncedattrial + 6000)
stoppedattrial = i %#ok<NASGU,NOPRT>
drawnow;
break;
end
end
timinginfo = timinginfo(:,:,1:i);
nrtrials = i;
%Beeper(800);
Screen('CloseAll');
%Beeper(1200);
if driftsync
% Restore original display settings:
Screen('Resolution', screenids(1), oldResolution(1).width, oldResolution(1).height, oldResolution(1).hz, oldResolution(1).pixelSize, 0);
Screen('Resolution', screenids(2), oldResolution(2).width, oldResolution(2).height, oldResolution(2).hz, oldResolution(2).pixelSize, 0);
end
fprintf('What you should see in the following plots for well synchronized displays:\n');
fprintf('The "drift" plots should either show a nice zero flat line or a flat line with\n');
fprintf('a small constant offset. Of course a bit of kind of gaussion noisyness has to be\n');
fprintf('expected in the system. What you should not see is some clear trend in one direction\n');
fprintf('or a sawtooth-like pattern. That would indicate drift between the display heads due\n');
fprintf('to missing sync across the heads.\n\n');
% Some plotting:
close all;
if (range(timinginfo(1, 1, :)) > 0) && (range(timinginfo(1, 2, :)) > 0)
plot(1:nrtrials, squeeze(timinginfo(1,1,:)), 'r', 1:nrtrials, squeeze(timinginfo(1,2,:)), 'b');
title('Beampositions for both displays: Red = Head 1, Blue=Head 2');
figure;
plot(1:nrtrials, squeeze(timinginfo(1,1,:)) - squeeze(timinginfo(1,2,:)));
title('Beamposition drift between displays:');
end
if testvblirqs
figure;
plot(1:nrtrials, squeeze(timinginfo(2,1,:)), 'r', 1:nrtrials, squeeze(timinginfo(2,2,:)), 'b');
title('VBL Interrupt timestamps for both displays: Red = Head 1, Blue=Head 2');
figure;
plot(1:nrtrials, squeeze(timinginfo(2,1,:)) - squeeze(timinginfo(2,2,:)));
title('VBL Interrupt timestamp drift between displays:');
end
return;
|