One thing to watch out for with WinTel setups is triple-buffering. Triple-buffering might be active even though it is neither advertised nor can it be disabled. In such a case, I found the following workaround useful:
kPsychBusyWaitForVBLBeforeBufferSwapRequest = 2^15;
Screen('Preference', 'ConserveVRAM', kPsychBusyWaitForVBLBeforeBufferSwapRequest);
However, this workaround adds a consistent one-frame delay at the output, which is and cannot be detected by PTB, and it burns CPU time. But otherwise, the PTB flip timing is reliable and timestamps are consistent - well, at least with the single-screen setup I have tested. Note that programs that rely on swapping between only 2 buffers on a higher level, e.g. when preserving the information in the buffers for reusing it in subsequent frames, might need further tweaking for making them triple-buffer safe.
Here is a program that makes triple-buffering visible:
function TripleBufferCheck
% Check for triple buffering.
% First, the program draws a patch in 3 consecutive frames at 3 positions on the screen - 1:left, 2:mid, 3:right.
% Then the program just flips between the buffers for a few seconds, without clearing the buffers in between.
% If there are only 2 buffers (aka double-buffering), we will see the patches flickering between 2 positions.
% Otherwise, if we have triple-buffering, we will see patches flickering between all 3 positions.
% There is also a small square at the top left that changes color while flipping.
SCREEN_NO = 0;
clear Screen
Screen('Preference', 'VBLTimestampingMode', -1);
Screen('Preference', 'Verbosity', 3);
Screen('Preference', 'VisualDebugLevel', 0);
Screen('Preference', 'SkipSyncTests', 1);
try
wnd = Screen('OpenWindow',SCREEN_NO,0);
[w,h] = Screen('WindowSize', wnd);
%--- Hide the mouse cursor, just in case there is some interference
% between cursor drawing and buffering.
HideCursor();
for x=-1:1
%--- Be sure that there are no pending flips anymore (at a very low
% level). Don't rely on what PTB thinks is going on, because this
% might be wrong due to triple-buffering.
WaitSecs(50e-3,'YieldSecs');
Screen('FillRect', wnd, 0);
Screen('FillRect', wnd, 255, repmat([w/2+w/3*x,h/2],1,2) + w/16*[-1,-1,1,1]);
Screen('Flip', wnd, 0, 2);
end
%--- Cycle through the buffers for a while in a consistent way, i.e. without
% flipping potentially too fast for making every buffer show (with
% triple-buffering, flip synchronization won't work correctly).
alarm = GetSecs() + 4;
while GetSecs()<alarm
WaitSecs(50e-3,'YieldSecs');
Screen('FillRect',wnd, round(rand(3,1)*255), [0,0,20,20]);
Screen('Flip', wnd, 0, 2);
end
ShowCursor();
sca();
catch e
ShowCursor();
sca();
rethrow(e);
end
end