Experiencing dropped frames when drawing many stimuli (~300) for cancellation task

Using Python: 3.6.13 and Psychopy 2021.2.3:

Hi all,
I’ve been trying to code a cancellation task in which the participants must put in a decent amount of effort even if it is ‘easy’. In order to "cancel’ the stimuli I want participants to click on the object and have it “disappear” by changing the opacity to 0. The aim of this task is to get participants to ‘work’ for a reward that they can use in the main task.

I have run into several issues regarding dropped frames due to how long it takes to draw many (300 stimuli, in my case).

My first two attempts were to utilize visual.TextStim and visual.ShapeStim, I created a list of stimuli and then appended each stimulus component to that list to draw from later.

The TextStim implementation:

    for stimNo in range(elemMax):
        elements.append(visual.TextStim(win = win, 
        name = 'element'+str(stimNo),
        text = 'T',
        font = 'Arial',
        height = misc.deg2pix(params['STIM']['textHeight']['value'], monitor),
        pos = (0,0),
        wrapWidth = None, 
        ori = 0,
        color = "white"))

#Inbetween code before trial starts running
Experiment loop starts here: 
        while frame < 60: #This is the individual loop for each trial
          for stim in elements:
            for stim in elements:
                if stim.opacity == 1:
                    if mouse.isPressedIn(stim, buttons=[0]):
                        stim.color = 'gray'
          frame += 1

#After a 'space' press break from the loop and reset the opacities to 1 and colours to white
#This happens outside of the individual trial loop, but also even omitting this code i still get the dropped frames

The ShapeStim implementation (The draw code is the same as TextStim so I have omitted it):

Tee = [(-0.1, -0.1), (0.1, -0.1), (0.1, 0.2), (0.2, 0.2), (0.2, 0.3), (-0.2, 0.3), (-0.2, 0.2), (-0.1, 0.2)]
 for Idx in range(elemMax):
        elements.append(visual.ShapeStim(win = win,
        vertices = Tee,
        fillColor = 'white',
        size = 100,
        pos = (0,0)))

Both of the above implementations take 150ms - 200ms to draw the stimuli, which has the consequence of 9-12 dropped frames per flip. I also tried a version in which instead of explicitly calling .draw() I used the .setAutoDraw(True) method so I could change attributes without having to explicitly redraw them in a loop, which didn’t make a difference in performance unfortunately.

I had a brief attempt at doing this with the ElementArrayStim component, where i created a T-like texture as shown below:

x = visual.ElementArrayStim(win = win,
    nElements = 300,
    fieldShape = 'sqr',
    elementMask = None,
    xys = positions,
    oris = 90,
    elementTex = array,
    sizes = 40)

while frame < 60*5: #5seconds
 frame += 1

Which gets the job done by drawing the 300 stimuli without dropping frames. But from my understanding, these stimuli do not have a .contains() method which makes it hard to make them interactive. At least for my purposes of changing their opacity and then changing it back due to a mouse click.

I was wondering if others had any advice on whether ElementArrayStim is the way to go, or if there is a more efficient way to work with the previously mentioned components (or others that will achieve the same goal – I did find that visual.GratingStim had better performance only dropping 3-4 frames per flip).

Happy to provide more context if necessary, through this troubleshooting process I was wondering if perhaps I’m hitting either a software or hardware limitation so any advice there would be great as well.
running psychopy.info.RunTimeInfo() doesn’t give me any causes for concern and my PC specs are CPU: I7-6850K, GPU: NVIDIA GTX1080.

Cheers, Andrew