Why does drawing an image for the first time slow down the sketch

Every time my code uses a new image, my sketch slows down considerably and I don’t understand why. I’m loading all of my images in the setup() function like everyone says I should, so I don’t understand why this is happening.

do you want to share the code and maybe some of the images? otherwise you will get the same answers like “everyone says”…

if you load big image with high resolution with 100’s megabytes it is normal to get kind of slow

explain your issue with code and image

A strong suspect would be transfer of the image pixels from the JVM to the GPU which will be done on first usage.

Hello,

Could you provide a minimal working example?
I don’t need the images just an idea of what size they are.

:)

Hello, thank you all for responding.
I apologize for the lack of information in my original post.
The sketch takes upwards of 3 minutes to fully load. I’m using the P2D renderer, each image is only around 200 KB and 2000x2000 pixels which I don’t think is that large? I’m loading them each with a for loop in setup like this.

//load images
  arrow = new PImage[9];
  for (int i = 1; i <= 8; i = i+1) {
    arrow[i] = loadImage("arrow000"+i+".png");
  }

200kb is the compressed size. 2000x2000 pixels is about 15mb of data that needs transferring and caching in a texture on first use.

I’m facing the same issue, I had to come up with a workaround.

My context is this: I have a collection of “scenes”, each having a list of sprites (lists of images), in some cases even drawn using multiple layers of PGraphics… quite complex!
The problem is that when I draw a new Scene for the first time, the sketch hangs (sometimes up to three or more seconds)

These solutions did not work:

  • pre-render images in setup()
  • pre-render images on a different thread: Processing protests that I’m not drawing from the main thread
  • … other 100’s I’ve tried but don’t remember :slight_smile:

To add further complexity, I’m loading images using PApplet.requestImage()

The only workaround I’ve found so far is to:

  • while images are not ready, draw a static splash screen: you cannot have fancy animations because your main draw thread will be blocked by the first rendering :frowning:
  • keep track if scenes are ready to be drawn in a boolean scenesAreReady variable
  • when they first become ready (i.e. all images have been loaded, see requestImage() docs in the reference) pre-render them in an off-screen, disposable PGraphics buffer
  • all subsequent draw() calls will be smooth

My draw() method:

...

if (!allScenesReady()) {
    drawSplashScreen();
} else {
    drawMain(getGraphics());
}

The allScenesReady() method:

boolean allScenesReady() {
    if (scenesAreReady) {
        // immediately return
        return true;
    }
    scenesAreReady = scenes.stream().allMatch(Scene::isReady);
    if (scenesAreReady) {
        // this gets called only the first time scenesAreReady == true
        initScenes();
    }
    return scenesAreReady;
}

This is how initScenes() is implemented:

void initScenes() {
    // ... some initializing code

    PGraphics dummyBuffer = createGraphics(width, height, P2D);
    dummyBuffer.beginDraw();
    drawMain(dummyBuffer);
    dummyBuffer.endDraw();
}

Finally, see how drawMain() accepts a PGraphics dest object, so I can decide where to draw (dummy buffer vs main screen)

void drawMain(PGraphics dest) {
  dest.background(255);
  drawScenes(dest);
}

It’s not the perfect solution, as the sketch can take a long time to properly initialize (my sketch is very complex!) but it is the only solution I’ve found so far…

Would this work?

void setup() { size(640, 480, P2D); }
void draw() {
  if(frameCount == 1) {
    image(a, width, height);
    image(b, width, height);
    // ... draw all images here
    return;
  }
  // image are on the GPU now, delays should be gone
  // ... rest goes here ...
}

The amount of images is limited by the GPU RAM though.

1 Like

Hello,

That condition will never be true in draw():

This will be true for the first frame in draw():

if (frameCount == 1)

Perhaps drawing the images in setup() first would also help.

:)

1 Like

Ok changed to ==. You got the idea :slight_smile:

I think it was mentioned earlier that drawing the images inside setup didn’t help with transferring them to the GPU to avoid later unexpected pauses.