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
|
function tonset = PredictVisualOnsetForTime(window, when, refreshinterval)
% tonset = PredictVisualOnsetForTime(window, when [, refreshinterval])
%
% Map a specific requested 'when' visual onset time, as you would pass it as
% 'when' parameter to Screen('Flip', window, when); to the estimated onset
% time of the "flipped" stimulus.
%
% By default, the refresh interval from Screen('GetFlipInterval', window);
% is used for calculation, but you can provide an optional
% 'refreshinterval' to override this choice.
%
% This function predicts the real onset time of your "flipped" stimulus,
% taking into account that Screen('Flip') will not show your stimulus at
% exactly the requested 'when' time, but it will synchronize stimulus onset
% to the display refresh cycle of your monitor, ie, it will wait for onset
% of the closest vertical blanking interval equal or later than 'when'.
%
% You can use the predicted 'tonset' to synchronize other modalities to
% visual stimulus onset. E.g., our sound driver PsychPortAudio can accept
% such a time as sound onset deadline in order to synch sound onset with
% visual stimulus onset...
%
% Of course if your stimulus is too complex to be finished with drawing
% until 'when' then Screen('Flip') will miss the deadline and this
% prediction will be wrong.
%
% Accuracy of prediction:
%
% On Linux with FOSS graphics drivers on Intel, AMD and NVidia hardware,
% and some dedicated SoC's, precision should be accurate to the low usecs
% range.
%
% On other systems that support timing via beamposition queries, the prediction
% should be accurate to better than 200 microseconds. On systems without
% beamposition queries, the prediction may be off by up to a millisecond
% worst case. On such systems we can't determine and correct for the
% duration of the vertical blanking interval, so the prediction will be a
% bit too early.
% History:
% 3-Jul-2007 Written. (MK)
% 4-Jan-2017 Fixes for OS builtin timestamping. (MK)
if nargin < 2
error('You must provide a "window" handle and a "when" target time!');
end
% Retrieve last known good VBL timestamp for onscreen window 'window':
wininfo = Screen('GetWindowInfo', window);
lastvbl = wininfo.LastVBLTime;
if lastvbl < 0
error('Sorry, can''t predict onset time, no valid previous flip timestamp.\nCall Screen(''Flip'') at least once before using this function!');
end
if nargin < 3
refreshinterval = [];
end
if isempty(refreshinterval)
% Retrieve measured monitor flip interval:
ifi = Screen('GetFlipInterval', window);
else
% Use provided refresh interval instead:
ifi = refreshinterval;
end
% Need to find first VBL after 'when':
if when <= 0
% Special case: Swap at next VSYNC:
% Convert into something we can handle...
when = lastvbl + 0.5 * ifi;
end
% Compute time delta in units of video refresh intervals between 'when' and
% the last known flip:
dt = (when - lastvbl) / ifi;
% Round 'dt' up to the closest integer greater than 'dt': This will be the
% index of the next refresh interval after 'when'. We add a small epsilon
% to make sure we don't get stuck at 'dt' itself if it should be too close
% to a vbl onset. In that case we would miss that deadline anyway...
dt = floor(dt) + 1;
% Compute corresponding vbl time for target flip video frame 'dt':
vbl = lastvbl + (dt * ifi);
% Ok, vbl is our best guess about VBL onset - and therefore bufferswap time
% of Screen('Flip', window, when);
% If this system supports beamposition queries then we can estimate the
% real visual onset time from the 'vbl' time by adding the duration of the
% VBL. If the system doesn't support them, then 'vbl' is our best estimate
% of onset. On Linux with FOSS drivers, the 'vbl' *is* already the onset
% timestamp, so no correction needed. Need for correction can be derived
% from SpecialFlags setting 16 (~ No OS builtin vblank timestamping).
if (wininfo.VBLEndline > 0) && (bitand(wininfo.SpecialFlags, 16) == 16)
% Known VBL endline and vbl is actual vbl start. We can calculate VBL
% duration and add it to our 'vbl' estimate.
vblduration = (wininfo.VBLEndline - wininfo.VBLStartline) / wininfo.VBLEndline * ifi;
tonset = vbl + vblduration;
else
% No knowledge about duration of VBL. We return 'vbl' as our best
% estimate, which is correct onset at least on Linux + FOSS:
tonset = vbl;
end
return;
|