Skip to content

Commit d80d5e0

Browse files
committed
EGLBE: Restore buf state when binding default FB
This is very subtle, but glBindFramebuffer(..., 0) should restore the current context's previous draw/read buffer state for the default framebuffer, as glXMake*Current() does. Swapping the buffers of a GLX drawable causes the EGL back end to create a new FBO to serve as the drawable's default framebuffer, with the new FBO containing the previous RBOs bound in reverse order. The default draw/read buffer for a new FBO is GL_COLOR_ATTACHMENT0, which the EGL back end uses as the front left buffer. Thus, if the default framebuffer for a drawable isn't bound when the drawable's buffers are swapped, then the FBO's initial draw/read buffer remains unchanged. If GL_BACK was active the last time the default framebuffer was bound, then calling glBindFrameBuffer(..., 0) after a buffer swap put VirtualGL into a weird state whereby it reported that GL_BACK was active, but the RBO corresponding to GL_FRONT was actually active. This issue caused Webots to flicker when rendering a camera view, and it may have affected other applications as well. Fixes #172
1 parent 5b2c1e8 commit d80d5e0

3 files changed

Lines changed: 61 additions & 10 deletions

File tree

ChangeLog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ of the form `egl{n}`, where `{n}` is a zero-based index, or by a DRI device
1515
path. A list of valid EGL device IDs and their associated DRI device paths can
1616
be obtained by running `/opt/VirtualGL/bin/eglinfo -e`.
1717

18+
4. Fixed an issue in the EGL back end whereby `glBindFramebuffer()`, when used
19+
to bind the default framebuffer, did not restore the previous draw/read buffer
20+
state for the default framebuffer. This issue was known to cause flickering in
21+
Webots when rendering a camera view, and it may have affected other
22+
applications as well.
23+
1824

1925
3.0.1
2026
=====

server/backend.cpp

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,25 +73,32 @@ static FakePbuffer *getCurrentFakePbuffer(EGLint readdraw)
7373
void bindFramebuffer(GLenum target, GLuint framebuffer, bool ext)
7474
{
7575
#ifdef EGLBACKEND
76+
const GLenum *oldDrawBufs = NULL; GLsizei nDrawBufs = 0;
77+
GLenum oldReadBuf = GL_NONE;
78+
FakePbuffer *drawpb = NULL, *readpb = NULL;
79+
7680
if(fconfig.egl)
7781
{
7882
if(framebuffer == 0)
7983
{
8084
if(target == GL_DRAW_FRAMEBUFFER || target == GL_FRAMEBUFFER)
8185
{
82-
FakePbuffer *pb = pbhashegl.find(getCurrentDrawableEGL());
83-
if(pb)
86+
drawpb = pbhashegl.find(getCurrentDrawableEGL());
87+
if(drawpb)
8488
{
85-
framebuffer = pb->getFBO();
89+
oldDrawBufs =
90+
ctxhashegl.getDrawBuffers(_eglGetCurrentContext(), nDrawBufs);
91+
framebuffer = drawpb->getFBO();
8692
ctxhashegl.setDrawFBO(_eglGetCurrentContext(), 0);
8793
}
8894
}
8995
if(target == GL_READ_FRAMEBUFFER || target == GL_FRAMEBUFFER)
9096
{
91-
FakePbuffer *pb = pbhashegl.find(getCurrentReadDrawableEGL());
92-
if(pb)
97+
readpb = pbhashegl.find(getCurrentReadDrawableEGL());
98+
if(readpb)
9399
{
94-
framebuffer = pb->getFBO();
100+
oldReadBuf = ctxhashegl.getReadBuffer(_eglGetCurrentContext());
101+
framebuffer = readpb->getFBO();
95102
ctxhashegl.setReadFBO(_eglGetCurrentContext(), 0);
96103
}
97104
}
@@ -107,6 +114,20 @@ void bindFramebuffer(GLenum target, GLuint framebuffer, bool ext)
107114
#endif
108115
if(ext) _glBindFramebufferEXT(target, framebuffer);
109116
else _glBindFramebuffer(target, framebuffer);
117+
#ifdef EGLBACKEND
118+
if(fconfig.egl)
119+
{
120+
if(oldDrawBufs)
121+
{
122+
if(nDrawBufs == 1)
123+
drawpb->setDrawBuffer(oldDrawBufs[0], false);
124+
else if(nDrawBufs > 0)
125+
drawpb->setDrawBuffers(nDrawBufs, oldDrawBufs, false);
126+
delete [] oldDrawBufs;
127+
}
128+
if(oldReadBuf) readpb->setReadBuffer(oldReadBuf, false);
129+
}
130+
#endif
110131
}
111132

112133

server/fakerut.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -994,10 +994,10 @@ int readbackTestMS(void)
994994

995995
XMapWindow(dpy, win);
996996

997-
clr.clear(GL_BACK);
998-
VERIFY_BUF_COLOR(GL_BACK, clr.bits(-1), "GL_BACK");
999997
clr.clear(GL_FRONT);
1000998
VERIFY_BUF_COLOR(GL_FRONT, clr.bits(-1), "GL_FRONT");
999+
clr.clear(GL_BACK);
1000+
VERIFY_BUF_COLOR(GL_BACK, clr.bits(-1), "GL_BACK");
10011001
glGenFramebuffers(1, &fbo);
10021002
glGenRenderbuffers(1, &rbo0);
10031003
glGenRenderbuffers(1, &rbo1);
@@ -1017,9 +1017,26 @@ int readbackTestMS(void)
10171017
VERIFY_FBO(fbo, GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, fbo,
10181018
GL_COLOR_ATTACHMENT1);
10191019
glBindFramebuffer(GL_FRAMEBUFFER, 0);
1020+
VERIFY_FBO(0, GL_BACK, GL_NONE, 0, GL_BACK);
1021+
checkBufferState(GL_BACK, GL_BACK, dpy, win, win, ctx);
1022+
clr.clear(0);
1023+
VERIFY_BUF_COLOR(0, clr.bits(-1), "GL_BACK");
1024+
// When using the EGL back end in VirtualGL 3.0 beta1 through 3.0.1, the
1025+
// following command will fail, because glBindFramebuffer(..., 0) didn't
1026+
// restore the previous draw/read buffer state for the default framebuffer.
1027+
// Swapping the buffers of a GLX drawable causes the EGL back end to
1028+
// create a new FBO to serve as the drawable's default framebuffer, with
1029+
// the new FBO containing the previous RBOs bound in reverse order. The
1030+
// default draw/read buffer for a new FBO is GL_COLOR_ATTACHMENT0, which
1031+
// the EGL back end uses as the front left buffer. Since the default
1032+
// framebuffer isn't bound when the buffers are swapped in the code above,
1033+
// the FBO's initial draw/read buffer remains unchanged. Thus, at this
1034+
// point in the code, VirtualGL reported that GL_BACK was active, but the
1035+
// RBO corresponding to GL_FRONT was actually active. As a result, the
1036+
// previous two commands affected the front buffer rather than the back
1037+
// buffer.
1038+
VERIFY_BUF_COLOR(GL_BACK, clr.bits(-1), "GL_BACK");
10201039
VERIFY_BUF_COLOR(GL_FRONT, clr.bits(-2), "GL_FRONT");
1021-
VERIFY_FBO(0, GL_FRONT, GL_NONE, 0, GL_FRONT);
1022-
checkBufferState(GL_FRONT, GL_FRONT, dpy, win, win, ctx);
10231040
checkFrame(dpy, win, 1, lastFrame);
10241041
checkWindowColor(dpy, win, clr.bits(-2));
10251042

@@ -2044,6 +2061,13 @@ int offScreenTest(bool dbPixmap, bool doSelectEvent)
20442061
printf("FBO->Window: ");
20452062
if(!(glXMakeContextCurrent(dpy, glxwin, glxwin, ctx)))
20462063
THROWNL("Could not make context current");
2064+
// The following command will fail unless the implementation of
2065+
// glXMake*Current() in the EGL back end restores the context's previous
2066+
// read buffer state for the default framebuffer. The multithreaded
2067+
// rendering test will fail unless the implementation of
2068+
// glXMake*Current() in the EGL back end restores the context's previous
2069+
// draw buffer state for the default framebuffer.
2070+
VERIFY_BUF_COLOR(0, clr.bits(-2), "Win");
20472071
CHECK_GL_ERROR();
20482072
checkCurrent(dpy, glxwin, glxwin, ctx, dpyw / 2, dpyh / 2);
20492073
clr.clear(GL_BACK);

0 commit comments

Comments
 (0)