RPi - Temp fix or workaround for ofSetBackgroundAuto?

#1

Hi all,

I’m working on a Raspberry Pi project (RPi 3 B+) with a high resolution screen (2560x1440) (OF version 0.10.0_linuxarmv6l). The project has very simple graphics, but needs the background to not automatically redraw.

Raspberry Pi’s ofSetBackgroundAuto is currently bugged and will continue to draw the background even when set to false (Github issue). The current workaround is to use FBOs - these work, but are a massive hit on my framerate (60fps -> 20fps).

Is there an adjustment to the openFrameworks source I can make to quick-fix the ofSetBackgroundAuto problem? I don’t know much about the source or re-compiling it so this may be unpractical.

Alternatively, is there a more efficient workaround than using FBOs? Or a more efficient way to use them? The performance impact comes from the fbo.draw() call in my draw() loop.

Many thanks,
Digl

#2

Weird, I wasn’t aware of this issue. I don’t have the time to look into this right now, but I just took a look at how the ofSetBackgroundAuto function is called - it basically calls the function on the current renderer. I’d look at what the current renderer is when using the rPi - and then looking into the ofSetBackgroundAuto function in the relevant renderer. Looking into the ofGLRenderer::startRender() , it seems to have a conditional for WIN32 platforms, my guess is that it needs a EGL specific conditional too for the backgroundAuto on the rPi. I’ll try to look into this next week but I can’t promise anything.

This is the relevant bit in the ofGLRenderer source code, I think.

void ofGLRenderer::startRender(){
	currentFramebufferId = defaultFramebufferId;
	framebufferIdStack.push_back(defaultFramebufferId);
	matrixStack.setRenderSurface(*window);
	viewport();
	// to do non auto clear on PC for now - we do something like "single" buffering --
	// it's not that pretty but it work for the most part

	#ifdef TARGET_WIN32
	if (getBackgroundAuto() == false){
		glDrawBuffer (GL_FRONT);
	}
	#endif

	if ( getBackgroundAuto() ){// || ofGetFrameNum() < 3){
		background(currentStyle.bgColor);
	}
}

Can you share the code for your fbo.begin(), fbo.end() and fbo.draw() code? AFAIK, if you don’t use ofClear() when starting the fbo calls, it should not clear the background - but I can’t comment on the performance hit.

#3

Thanks, have played around with it a bit - seems RPi’s renderer is redrawing the background automatically and needs an exception like the one for WIN_32. This is a bit out of my depth though - I’m not sure what the equivalent process is for RPi’s renderer (the Pi can’t compile “glDrawBuffer(GL_FRONT)”). Any ideas?

Also - the FBOs are working as expected (i.e., not cleaning the background), but the performance hit is what makes them unappealing. The code is stripped back for testing, just with

fbo.allocate(...);
fbo.begin();
ofBackground(0);
fbo.end();

in setup, and

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

in draw.

#4

Ok so I’ve done some digging:

• Apparently the RPi buffer auto-clearing is a performance optimisation [link]
• You can manually preserve the buffer by setting EGL_SWAP_BEHAVIOR to EGL_BUFFER_PRESERVED via eglSurfaceAttrib [link]
• You need to ensure the EGL_SWAP_BEHAVIOR_PRESERVED_BIT is included in the EGL_SURFACE_TYPE config [link]

I’ve given it a try:
In ofAppEGLWindow::createSurface() (replacing attribute_list_framebugger_config setup):

	// each attribute has 2 values, and we need one extra for the EGL_NONE terminator
	// Adding an extra two for our RPi background quickfix
	EGLint attribute_list_framebuffer_config[settings.frameBufferAttributes.size() * 2 + 3 + 2];
	iter = settings.frameBufferAttributes.begin();
	iterEnd = settings.frameBufferAttributes.end();
	i = 0;
	for(; iter != iterEnd; iter++) {
		attribute_list_framebuffer_config[i++] = iter->first;
		attribute_list_framebuffer_config[i++] = iter->second;
	}
	attribute_list_framebuffer_config[i++] = EGL_RENDERABLE_TYPE;
	attribute_list_framebuffer_config[i++] = glesVersion; //openGL ES version
	// Add the surface type attribute
	attribute_list_framebuffer_config[i++] = EGL_SURFACE_TYPE;
	// Assuming we need to include the default EGL_WINDOW_BIT?
	// I can't see anywhere else this attribute is modified past the defaults.
	attribute_list_framebuffer_config[i++] = EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
	attribute_list_framebuffer_config[i] = EGL_NONE; // add the terminator

In ofAppEGLWindow::createSurface() (at the end of the function):

	result = eglSurfaceAttrib(eglDisplay, eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
	if(result == EGL_FALSE){
		EGLint error = eglGetError();
		ofLogError("ofAppEGLWindow") << "eglSurfaceAttribute failed: " << eglErrorString(error);
		return false;
	}

Everything compiles correctly, my recompiled test app starts up as normal, but still getting the auto-cleared background. Seems to be something else in the way, I don’t know EGL well enough to have any inklings.

Hopefully this gives you a couple of leads if you find some time to look into it.

#5

Did you come across any solve for this?

#6

Unfortunately not. I ended up using the FBO workaround, (as oweno describes here).

There’s an issue open for this on Github: