Multiple windows with "useFBO=True"

Hi,

We have a projector displaying a psychopy window using the ProjectorFramePacker (to get a 60hz output split into 3 subframes for 180hz). This requires leaving “useFBO=True” for that window.

Since the projector will be projected into a microscope, I have a second window on the monitor that mirrors the projector window. Prior to using the framepacking, I followed the advice in this thread, and leaving useFBO off worked there. Now that I’m forced to use FBO for the projector window, creating a second window and drawing to it causes the first window to not draw properly.

Does anyone have any suggestions on how to work around this? Any help would be appreciated. Thanks in advance.

Alex

1 Like

How fast is this computer and graphics card? On a fast card I wouldn’t expect the FBO to slow things down

Very fast. We purposely built this computer for visual stimuli. It’s running an i5-7500 with a gtx 1070. FBO doesn’t cause any slow downs, but is required to use the framepacking. The problem is that when having FBO with 2 separate windows, one of the windows does not draw properly, so I’m at an impasse.

Ah, sorry, I misread the thread you pointed to. I don’t know, off the top of my head, what would cause an FBO to render badly dependent on the number of windows :-/

1 Like

Hello,

The problem is that when having FBO with 2 separate windows, one of the windows does not draw properly, so I’m at an impasse.

Can you describe what is not being drawn correctly?

1 Like

The second window will draw the stim normally. The first window flickers between black and background, and the stim never appears.

Hello Alexander,

I am able to reproduce the issue on my PC. I think it’s due to the stimuli’s “__selectWindow” method binding to the back buffer instead of the framebuffer before drawing. You can correct the issue by doing the following hack …

# add these imports
import pyglet
GL = pyglet.gl
from psychopy.visual import globalVars

...

# when drawing stimuli
win1.winHandle.switch_to()
globalVars.currWindow = win1
GL.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, win1.frameBuffer)

# draw your stimuli to window 1
stim1.draw(win1)
    
win2.winHandle.switch_to()
globalVars.currWindow = win2
GL.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, win2.frameBuffer)

# draw your stimuli to window 2
stim2.draw(win2)
    
win1.flip()
win2.flip()

You might want to consider overriding the stim class’s “_selectWindow” to a dummy function that does nothing, removing the redundant switch_to().

2 Likes

That fixed it! Thank you very much for your help.

Hi Alex,

I’m trying to use the ProjectorFramePacker to split 60Hz into 180Hz with a DPL. But I couldn’t figure out how I may use it to create a simple flickering rectangle that flicker at 180hz.

I have something like this now, but somehow it doesn’t really behave as expected:

mywin = visual.Window([912,1140],fullscr=True, monitor=“DLP”, units=“cm”, screen=2, useFBO= True)
framePacker = ProjectorFramePacker(mywin)
photodiode = visual.Rect(win=mywin,width = 10,height = 10,pos = [0, 0],lineColor = [1,1,1],fillColor = [1,1,1])

while True:
photodiode.contrast = -1*photodiode.contrast
photodiode.draw()
framePacker.startOfFlip()

Any help would be appreciated!
Huayi

Hi Huayi,

The ProjectorFramePacker class is designed so that it does the work of frame packing behind the scenes and allows you to draw your stims as you normally would. Assuming that your DLP is also setup to split RGB frames into 3 frames, it should work out of the box.

After creating the ProjectorFramePacker instance, it shouldn’t need any touching. Instead, flip your window normally.

Try this:

mywin = visual.Window([912, 1140], 
                      fullscr=True,
                      monitor="DLP",
                      units="cm",
                      screen=2,
                      useFBO= True)
framePacker = ProjectorFramePacker(mywin)

photodiode = visual.Rect(win=mywin,
                         width=10,
                         height=10,
                         pos=[0, 0],
                         lineColor=[1, 1, 1],
                         fillColor = [1, 1, 1])

while True:
    photodiode.contrast *= -1
    photodiode.draw()
    mywin.flip()

Hopefully this works. Out of curiousity, what display are you using for the frame packing?

Alex

1 Like

Hi Alex,

Thanks for the the code! I tried the code and I’m reading the response from a photodiode. I get 60Hz flickering instead of 180HZ for the flickering. It seems that packing packs 3 of the same frame into one instead of the on & off frames. Having said that, I’m not sure if I’m setting up my lightcrafter (pattern sequence mode) right. Do you use lightcrafter for your experiment?

Cheers

Huayi

We also use a lightcrafter 4500. If you’re running it at 180 hz, you’re limited to 7 bits of color depth (if you’re just alternating between black and white, this isn’t an issue). I’ve attached a screenshot of our pattern sequence setup for 180 hz. At 7 bits, you can get it up to 222 hz, I can give you the timings for that if you’d like.

Hi Alex,

Sorry somehow I missed out on your last reply. We have the same lightcrafter! May I also ask for your graphic card setting? We have Nvidia GTX970. Are you setting it to 60HZ & 32bits to play at 180HZ?

Actually there’s another strange thing. I’ve noticed that with the lightcrafter screen as an extended desktop, if I play the flicker stimuli with psychopy, then if I open up a window (like a folder/ chrome) on the original desktop, then the flashing pauses until the window is fully opened up. But I don’t have this problem if I set the contrast to be always 1, i.e. when there’s no flashing. Do you have similar problem? I’m using Windows7.

Thanks for helping me!
Huayi

Hi Huayi,

We use a similar GPU. To get 180 hz out of the lightcrafter, we set our graphics card to 60 hz and 32 bits, on the default settings but with the resolution set to 912x1140 (required for pattern sequence mode). If you want to get your lightcrafter up to 222 hz (the max with 7 bit color depth), here are the settings we use for that:

I’m not sure what the issue with the pausing is. My guess is that when the window is opening up, the OS steals the focus from the GPU to draw the updates of the window so that psychopy can’t update it’s window. The reason you don’t see it when there’s no flashing is because even if the psychopy window were to stop drawing, because each frame is the same it wouldn’t be noticeable.

I’m not able to test it on my computer yet, but soon as I can I will and let you know. My suggestion would be to turn off the aero effect in Windows 7. We saw some noticeable improvements in performance turning that off, as before frames would consistently get dropped.

Have you been able to get 180 hz working?

Alex

Hi Alex,

I’ve tried the 180Hz method from your previous post and it seems to work. But as you said the frame dropping was quite concerning. It’s a great tip to turn off aero effect. It improved frame dropping a lot. But still, I notice that if I switch windows more frequently, then I get more frame dropping. Do you have frame dropping issue still?

Cheers
Huayi

Hi Alex,

Some updates. I realized that the frame dropping after turning off aero effect is largely caused by opening & closing other windows on the computer. I’ve tried setting pythonw to max performance on nvidia control panel but it didn’t change anything. I’ve also tried setting python’s process priority to high, but also didn’t eradicate the problem. I suppose I just need to make sure I don’t touch anything during stimulus presentation.

Best,
Huayi

Hi mdc,

I’ve been using your suggestion now for several months with much success. I’ve run into a new problem though, and was wondering if you could offer some suggestions.

Using the frame packing, it’s no issue to have the primary projector running at 180hz, and on the secondary display to monitor the output, we draw 1 in 3 frames, for 60 hz, However, the projector is capable of being pushed to much higher frequencies. Without using the secondary window, it runs with no issue, but when we do use it we are capped at 180 hz (i.e. 3x the max frequency of the monitor, drawing 1/3 frames).

My initial thought was to simply disable waitBlanking on the secondary monitor in order to freely draw on the primary. This hasn’t worked though, and appear to not change anything. I’ve tried different window configurations, but nothing seems to work. Any help would be greatly appreciated.

Thanks,
Alex

Hello again,

I’m glad things have been working.

My thought would be that disabling waitBlanking would be enough. While I don’t have a projector system, I’ve used displays that run at different frequencies with success by doing so. I’m not familiar with PsychoPy’s frame packing implementation, but I think the answer might be found there. The quick hacks I provided might interact with the framepacking library causing unexpected results. It might be worth contacting the authors of the package to see if they have insight.

1 Like