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.

Revisions

  1. dxjones created this gist Jan 8, 2015.
    235 changes: 235 additions & 0 deletions Demo_FlipBug.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,235 @@
    % 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');