Skip to content

Instantly share code, notes, and snippets.

@dxjones
Created January 8, 2015 22:26
Show Gist options
  • Select an option

  • Save dxjones/75640b579b003e42f30b to your computer and use it in GitHub Desktop.

Select an option

Save dxjones/75640b579b003e42f30b to your computer and use it in GitHub Desktop.
Demo_FlipBug.m
% Demo_FlipBug.m
%
% 2015-01-08 [email protected]
%
% set ShowBug to false to avoid missed Flips
% set ShowBug to true to demonstrate missed Flips
ShowBug = true; % see line #75
try
Priority(9);
w = Screen('OpenWindow', 0);
FlipInterval = Screen('GetFlipInterval', w);
winfo = Screen('GetWindowInfo', w);
vblank = winfo.VBLStartline;
vtotal = winfo.VBLEndline;
% - - - - -
r = Screen('Rect', 0);
ScreenHeight = RectHeight(r);
ScreenWidth = RectWidth(r);
cx = ScreenWidth/2;
cy = ScreenHeight/2;
zx = cx - (vtotal/2);
zy = cy - (vtotal-vblank)/2;
radius = 0.45 * min(ScreenHeight, ScreenWidth);
x0 = (ScreenWidth/2) - (vtotal/2);
x1 = x0 + vtotal;
x_vblank = x0 + (x1-x0) * (vblank/vtotal);
y0 = 0.10 * ScreenHeight;
y1 = y0 + 0.80 * ScreenHeight;
y_vblank = y1 - (y1-y0) * (1/1.5);
% - - - - -
N = 1 + vtotal;
beam = false(N,1);
vt = zeros(N,1);
m = zeros(N,1);
bp = zeros(N,1);
t_pre = zeros(N,1);
t_post = zeros(N,1);
t_mid = zeros(N,1);
vt_pre = zeros(N,1);
vt_post = zeros(N,1);
vt_mid = zeros(N,1);
% main loop includes random delays to get a variety of beam positions
% "beamcount" controls how many different beam positions we need
% Caution: main loop will become very slow if beamcount > 0.95 * vtotal
beamcount = 0.95 * vtotal;
VBL_timestamp = 0;
while true
if nnz(beam) >= beamcount
break
end
if KbCheck
break
end
% simple animation shows progress through loop
y = nnz(beam);
Screen('DrawLine', w, 0, 100,y, 400,y);
% wait a random delay
delay = rand * FlipInterval;
WaitSecs(delay);
if ShowBug
WaitSecs(2*FlipInterval);
end
% wait for a beampos we haven't seen before
while true
t0 = GetSecs;
beampos = Screen('GetWindowInfo', w, 1);
t1 = GetSecs;
b = 1 + beampos;
if ~beam(b)
beam(b) = true;
break
end
break
end
% Flip
when = 0;
% when = GetSecs + 0.010;
[VBL_timestamp Stim_timestamp Flip_timestamp Missed Beampos_after_Flip ] = Screen('Flip', w, when,1);
% Calculate Flip Time
% (normally, this would be done before the Flip)
t_pre(b) = t0;
t_post(b) = t1;
t_mid(b) = (t0 + t1) / 2;
vt_pre(b) = CalculateFlipTime(t_pre(b), beampos, vblank, vtotal, FlipInterval);
vt_post(b) = CalculateFlipTime(t_post(b), beampos, vblank, vtotal, FlipInterval);
vt_mid(b) = CalculateFlipTime(t_mid(b), beampos, vblank, vtotal, FlipInterval);
FlipDelta = VBL_timestamp - vt_mid(b);
% record actual VBL, etc.
vt(b) = VBL_timestamp;
m(b) = Missed;
bp(b) = Beampos_after_Flip;
% - - - - -
px = x0 + (x1-x0) * (b/vtotal);
py = y1 - (y1-y0) * ((Beampos_after_Flip - vblank) / (1.5*(vtotal - vblank)));
Screen('DrawLine', w, 128, x0,y0, x0,y1);
Screen('DrawLine', w, 128, x1,y0, x1,y1);
Screen('DrawLine', w, 128, x0,y0, x1,y0);
Screen('DrawLine', w, 128, x0,y1, x1,y1);
Screen('DrawLine', w, 128, x_vblank,y0, x_vblank,y1);
Screen('DrawLine', w, 128, x0,y_vblank, x1,y_vblank);
if FlipDelta < (FlipInterval/2)
color = [0 255 0 255];
else
color = [255 0 0 255];
Screen('FillRect', w, color, [px-1 y1+10 px+1 y1+110]);
end
Screen('FillRect', w, color, [px-1 py-3 px+1 py+3]);
% - - - - -
end
% hocus-pocus to make sure we close all windows
wlist = Screen('Windows');
Screen('CloseAll');
Priority(0);
catch e
CatchGraphicsError(e, 'BeginGraphics');
% hocus-pocus to make sure we close all windows
wlist = Screen('Windows');
Screen('CloseAll');
Priority(0);
end
scanline = 0:vtotal;
scanlines_per_msec = (vtotal+1) / (1000 * FlipInterval);
% guess at beampos deadline for successful flips
vdeadline = 0.75 * vblank;
%%
% Figure 1 shows Beampos before/after Flip
%
% Notice Beampos after Flip is almost always ...
% between vblank and vtotal, occasionally wraps around
%
% adjust returned beampos to wrap around past the end of vtotal
X = bp < (vtotal/2);
bp( X ) = bp( X ) + (1+vtotal);
figure(1);
plot(vtotal*[0 1],[0 0],'k:', ...
vtotal*[0 1], vblank*[1 1],'k:',...
vtotal*[0 1], vtotal*[1 1],'k:', ...
[0 0], vtotal*[0 1],'k:', ...
vdeadline*[1 1],vtotal*[0 1],'g:', ...
vblank*[1 1], vtotal*[0 1], 'k:', ...
vtotal*[1 1], vtotal*[0 1], 'k:', ...
scanline(beam),bp(beam),'r.');
% vblank - scanlines_per_msec*[1 1], vtotal*[-1 2],'r:', ...
% vblank - scanlines_per_msec*[2 2], vtotal*[-1 2],'r:', ...
% vblank - scanlines_per_msec*[3 3], vtotal*[-1 2],'r:', ...
% vblank - scanlines_per_msec*[4 4], vtotal*[-1 2],'r:', ...
% vblank - scanlines_per_msec*[5 5], vtotal*[-1 2],'r:', ...
% vblank - scanlines_per_msec*[6 6], vtotal*[-1 2],'r:', ...
% vblank - scanlines_per_msec*[7 7], vtotal*[-1 2],'r:', ...
xlabel('Beampos before Flip');
ylabel('Beampos after Flip');
text(vtotal/2, vblank, 'VBLANK');
text(vtotal/2, vtotal, 'VTOTAL');
axis([0 vtotal vblank-10 vtotal+10]);
axis square
%%
% Figure 2 shows accuracy of Calculated Flip Time
%
% Notice blue data points are very close to zero
delta_pre = vt - vt_pre;
delta_post = vt - vt_post;
delta_mid = vt - vt_mid;
figure(2);
plot(vtotal*[0 1],[0 0],'k:', ...
vtotal*[0 1],1000*FlipInterval*[1 1],'k:', ...
vtotal*[0 1],(vtotal+1)*[1 1],'k:', ...
vdeadline*[1 1],1000*FlipInterval*[-1 2],'g:', ...
vblank*[1 1],1000*FlipInterval*[-1 2],'k:', ...
vtotal*[1 1],1000*FlipInterval*[-1 2],'k:', ...
scanline(beam),1000*delta_pre(beam),'g.', ...
scanline(beam),1000*delta_mid(beam),'b.', ...
scanline(beam),1000*delta_post(beam),'r.');
figure(2), axis([0 vtotal -0.2 0.2]);
xlabel('Beampos before Flip');
ylabel('Flip Time Prediction Error (msec)');
title('Flip Time Prediction Error ... +ve means actual Flip occured later');
%%
% Figure 3 highlights missed Flips
figure(3);
plot(vtotal*[0 1],[0 0],'k:', ...
vtotal*[0 1],1000*FlipInterval*[1 1],'k:', ...
vtotal*[0 1],(vtotal+1)*[1 1],'k:', ...
vdeadline*[1 1],1000*FlipInterval*[-1 2],'g:', ...
vblank*[1 1],1000*FlipInterval*[-1 2],'k:', ...
vtotal*[1 1],1000*FlipInterval*[-1 2],'k:', ...
scanline(beam),1000*delta_pre(beam),'g.', ...
scanline(beam),1000*delta_mid(beam),'b.', ...
scanline(beam),1000*delta_post(beam),'r.');
figure(3), axis([0 vtotal 1000*FlipInterval-0.2 1000*FlipInterval+0.2]);
xlabel('Beampos before Flip');
ylabel('Flip Time Prediction Error (msec)');
title('Flip Time Prediction Error ... (Missed Flips) ... +ve means actual Flip occured later');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment