Understanding the flip() method

Hello,
I am studying code generated from the PsychoPy builder (as a practice exercise) and just noticed something strange. I 'd like to present a stimulus 0.5s after the beggining of a given trial. The builder generates the following piece of code:

t = trialClock.getTime()
if t >= 0.5 and stim.status == NOT_STARTED:
        # keep track of start time/frame for later
        stim.tStart = t
        stim.frameNStart = frameN  # exact frame index
        stim.setAutoDraw(True)

if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
        win.flip()

On LCD monitors, the refresh is a flood fill from top to bottom. Does the flip() method correspond to top (onset of refresh cycle, which I suspect) or bottom (end of refresh cycle)?

In a second exercise, I chose to present the stimulus at t = 0.2s during 0.2s. The builder then generates the following:

if t >= 0.2 and stim.status == NOT_STARTED:
            # keep track of start time/frame for later
            stim.tStart = t
            stim.frameNStart = frameN  # exact frame index
            stim.setAutoDraw(True)
frameRemains = 0.2 + 0.2- win.monitorFramePeriod * 0.75  # most of one frame period left
if stim.status == STARTED and t >= frameRemains:
            stim.setAutoDraw(False)

I am confused. Why is ā€˜-win.monitorFramePeriod * 0.75ā€™ added in this case?

Thanks for your help on this!

1 Like

The flip() method returns when the back buffer is released by the driver (if vsync is enabled), which usually proceeds the end of the refresh cycle.

Iā€™m not to sure what the code in the second question is doing though.

So the flip() method returns the end of the refresh cycle? In other words, the code continues after a flip() call when the refresh cycle is finished?
@Michael could you then clarify what the code generated by the Builder is doing? Many thanks and happy new year PsychoPy folks!

The time between the physical refresh and the flip returning depends on the monitor, which can take additional time after the graphics card has finished its work (and the graphics card and PsychoPy would never know). To know the lag between flip() returning and the screen updating you have to use a physical device (e.g. blackboxtoolkit). As an example, I have 144Hz Iiyama lcd gaming monitor. In ā€œDirect Driveā€ mode it flood fills from top and hs minimal lag behind the flip() call (photodiode detects stimulus 2.5ms after flip finishes). BUT in Game mode or Movie mode thereā€™s a roughly 1 frame delay and (bizarrely) the screen fills from the bottom! No software package can tell what post-processing your monitor does so you need to measure it.

The book by me and Mike has more info about monitors and timing.

The code about subtracting win.monitorFramePeriod * 0.75 is just PsychoPy deciding whether or not it should try and squeeze in another frame given a time-based stimulus duration. If we have a 16.67ms refresh period and weā€™re 14ms from the deadline time then present another frame, but if weā€™re at 2ms remaining then donā€™t.

Thanks Jon for this clarification and for pointing out the crazy effects of different monitor modes! I currently donā€™t have the material (photodiode) to measure this. If I understand correctly, the flip() is returned by the GPU, and should thus correspond to the onset of a refresh cycle (disregarding any post-processing of the monitor). Am I correct?

Yes, roughly that. But if you need it to be precise then you do need hardware