ofFbo gets cleared when an Android app goes to the background


#1

Hi, my app uses ofFbo and it seems to work fine on Android in general.

However, when an app goes to the background and then come back to the foreground, I see a blank fbo.

It works again if I redraw things to the fbo using fbo.begin() and fbo.end().

Here’s a simple code you can test.


ofFbo fbo;

//--------------------------------------------------------------
void ofApp::setup(){

    fbo.allocate(ofGetWidth(), ofGetHeight(), GL_RGBA);
    fbo.begin();
    ofClear(255,255,255, 0);
    fbo.end();
    
    fbo.begin();
    ofSetColor(255, 0, 0);
    ofDrawEllipse(ofGetWidth()/2, ofGetHeight()/2, ofGetWidth(), ofGetHeight());
    fbo.end();
}

//--------------------------------------------------------------
void ofApp::update(){
    
}

//--------------------------------------------------------------
void ofApp::draw(){
    
    fbo.draw(0, 0);
}

Can any Android users confirm this problem please?
I would appreciate if anyone can guide me on how to fix this.
Thank you in advance!


#2

Android kills all GL resources when the app goes to the background, OF tries to recover as much as it can automatically, for example ofImage, ofTruetypeFont, ofVboMesh and anything that keeps a copy in ram is recovered automatically when the app comes to the foreground again but for FBOs we don’t have anyway of knowing what was there before so you should recover them yourself when the app goes back to the foregroung again using the reloadTextures() callback in ofApp


#3

I see, Thank you for you answer @arturo

So, if I want to accurately recover FBO without redrawing things into it(Let’s say the drawing constantly changes, so redrawing to FBO doesn’t work).

Can the below strategy work?

  1. copy FBO’s pixels to ofImage as soon as the app goes to the background(I think ofApp::pause() can listen to this),

  2. and then copy the pixels back to FBO again(using fbo.allocate(), fbo.begin() and fbo.end()) as soon as the app comes back to the foreground.

Does it makes sense? Do you think it will work?
Thank you!


#4

I just tested this on an Android device and here’s what I found.

  1. If I copy FBO’s pixels to ofImage through ofApp::pause() listener, it couldn’t copy FBO. I think the FBO gets cleared before ofApp::pause() gets called.

  2. If I copy FBO’s pixels to ofImage through ofApp::touchDown() listener and manually copy FBO by touching the screen, it worked well.

And here’s the code I used to test

ofFbo fbo;
ofImage img;

//--------------------------------------------------------------
void ofApp::setup()
{
    fbo.allocate(ofGetWidth(), ofGetHeight(), GL_RGBA);
    fbo.begin();
    ofClear(255,255,255, 0);
    fbo.end();

    fbo.begin();
    ofSetColor(255, 0, 0);
    ofDrawEllipse(ofGetWidth()/2, ofGetHeight()/2, ofGetWidth(), ofGetHeight());
    fbo.end();
}

//--------------------------------------------------------------
void ofApp::draw()
{
    if (fbo.isAllocated())
        fbo.draw(0, 0);
}

//--------------------------------------------------------------
void ofApp::pause()
{
   //if below code is called in advance(e.g. by touchDown()), it worked well. 
    ofPixels pixels;
    fbo.readToPixels(pixels);
    img.setFromPixels(pixels);
    fbo.clear();
}

//--------------------------------------------------------------
void ofApp::reloadTextures()
{
    img.update();

    fbo.allocate(img.getWidth(), img.getHeight(), GL_RGBA);
    fbo.begin();
    ofClear(255,255,255, 0);
    fbo.end();

    fbo.begin();
    img.draw(0, 0);
    fbo.end();

    img.clear();
}

So the problem is ofApp::pause() seems to be called after FBO gets cleared. Would there be any other way to listen to the app going to the background? (before FBO gets cleared)

Any guidance would be appreciated!


#5

that’s strange doing it in pause should work, which OF version are you using?


#6

I’m using OF v0.9.8 release version.


#7

Can any Android user try the code and see if it works?
It will be very helpful. Thank you so much in advance!!


#8

tried your test-code on current master with same result: white screen when app resumes.

seems your image is empty after resume. (guess it has no pixels in ram)

simply drawing that shape again into the fbo in reloadTextures() works.


#9

Hi, Thank you very much for your testing.

But If I simply load and draw an image(using ofImage) and then come back from the background, the image draws perfectly fine.

And if you cut the code inside ofApp::pause() and paste it onto ofApp::touchDown() and then manually touch the screen before an app goes to the background, it works fine when you come back to the foreground which makes me think the FBO gets cleared before ofApp::pause() gets called.

But @arturo thinks it should work so I really don’t know what is causing the problem.


#10

sorry, this callbacks are kind of deprecated but still in the examples, can you try using unloadGL() to save the GL state and reloadGL() to recover it?

pause / resume / stop can still be used to detect when the app goes to the background foreground but the GL context might have been deleted already or not ready yet in those


#11

Thanks for your suggestion.
I tried using unloadGL() and reloadGL() but it still doesn’t work.

I still hope to find a solution to save the FBO automatically before an app going to the background…