Repository: psychopy/psychopy

Issue:
win.multiFlip() misbehaving?
Three issues:

1)

I get flickering when the display should be solid (as I interpret the intended behavior, based on the doc string description "Flips multiple times while maintaining display constant."):

```
from psychopy import visual
win = visual.Window()
stim = visual.ImageStim(win)
#stim.autoDraw = True
stim.draw()
win.multiFlip(15)
```

 The display of the stim is solid (no flicker) if autoDraw is True:

```
from psychopy import visual
win = visual.Window()
stim = visual.ImageStim(win)
stim.autoDraw = True
#stim.draw()
win.multiFlip(15)
```

2)

This line looks odd -- change to `or not int(flips) == flips`:

```
if flips < 1 and int(flips) == flips:
    logging.error("flips argument for multiFlip should be a positive integer")
```

3)

multiFlip is not documented online



Discussion:
If `autoDraw` is `False`, the first flip in `multiFlip()` would actually draw the box; the second would blank the screen; the third would draw it again; etc. With `autodraw = True`, the stimulus would be drawn before every flip. I don't know what's going on there, as my understanding of PsychoPy's drawing/OpenGL functions is very limited.

The problem with multiflip is that it uses the concept of flipping but not clearing the framebuffer (rather than flipping and redrawing all the objects). Flipping but not clearing is unpredictable - on some cards it literally swaps the back and front buffers (so your stimulus flashes on and off each frame) but on some cards it populates the back buffer with a copy of the (new) front buffer (so your stimulus will stay). The latter is the more useful behaviour for us but I don't know how to detect if that happened.

I'd personally recommend not using multiflip!

Thanks for the clarification, Jon!
Should `multiFlip` better be removed from the codebase, then? Or we should at least add a big fat red warning in the code somehow..? :)

I think a warning is a good idea. This is the reason that multiflip is not documented online, but documenting and saying that behaviour is unpredictable seems a better plan.


Resolving patch:
diff --git a/psychopy/visual/window.py b/psychopy/visual/window.py
--- a/psychopy/visual/window.py
+++ b/psychopy/visual/window.py
@@ -698,15 +698,23 @@ def update(self):
 
     def multiFlip(self, flips=1, clearBuffer=True):
         """
-        Flips multiple times while maintaining display constant.
+        Flip multiple times while maintaining the display constant.
         Use this method for precise timing.
 
+        WARNING: This function should not be used. See the `Notes` section
+        for details.
+
         :Parameters:
 
-            flips: number of monitor frames to flip image.
-                Window.multiFlip(flips=1) is equivalent to Window.flip().
+        flips: int, optional
+            The number of monitor frames to flip. Floats will be
+            rounded to integers, and a warning will be emitted.
+            ``Window.multiFlip(flips=1)`` is equivalent to ``Window.flip()``.
+            Defaults to `1`.
 
-            clearBuffer: as in Window.flip(). This is applied to the last flip.
+        clearBuffer: bool, optional
+            Whether to clear the screen after the last flip.
+            Defaults to `True`.
 
         Example::
 
@@ -721,18 +729,30 @@ def multiFlip(self, flips=1, clearBuffer=True):
             myWin.multiFlip(flips=2)
             # Show blank screen for 3 frames (because buffer was cleared above)
             myWin.multiFlip(flips=3)
-        """
 
-        #Sanity checking
-        if flips < 1 and int(flips) == flips:
+        :Notes:
+        This function can behave unpredictably, and the PsychoPy authors
+        recommend against using it.
+        See https://github.com/psychopy/psychopy/issues/867 for more
+        information.
+
+        """
+        if flips < 1:
             logging.error("flips argument for multiFlip should be "
                           "a positive integer")
+
+        if flips != int(flips):
+            flips = int(round(flips))
+            logging.warning("Number of flips was not an integer; "
+                            "rounding to the next integer. Will flip "
+                            "%i times." % flips)
+
         if flips > 1 and not self.waitBlanking:
             logging.warning("Call to Window.multiFlip() with flips > 1 is "
                             "unnecessary because Window.waitBlanking=False")
 
         #Do the flipping with last flip as special case
-        for _junk in range(flips-1):
+        for _ in range(flips-1):
             self.flip(clearBuffer=False)
         self.flip(clearBuffer=clearBuffer)
 


Test patch: