diff --git a/ChangeLog.md b/ChangeLog.md
index a6062920..6829b42b 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -9,6 +9,11 @@ not added to the list of extensions returned by
`glXQueryServerString(..., GLX_EXTENSIONS)` unless the underlying EGL
implementation supported v1.5 or later of the EGL API.
+2. If `VGL_SYNC` is enabled, the X11 Transport now reuses the 3D application's
+X display connection(s), which may prevent a 3D application running with
+VirtualGL from exceeding the X server's connection limit if the application
+opens an excessive number of OpenGL windows.
+
3.1.1
=====
diff --git a/doc/advancedconfig.txt b/doc/advancedconfig.txt
index 15ce84e9..3445f29b 100644
--- a/doc/advancedconfig.txt
+++ b/doc/advancedconfig.txt
@@ -852,6 +852,16 @@ previous method:
machine other than the VirtualGL server. It is strongly recommended that
''VGL_SYNC'' be used only in conjunction with an X proxy running on the
VirtualGL server.
+ {nl}{nl}
+ In order to implement frame spoiling, and also to allow the last frame to be
+ transported while the current frame is being rendered and read back,
+ VirtualGL's built-in image transports use a separate "transport thread". To
+ ensure thread safety, the X11 Transport normally creates multiple X display
+ connections for each OpenGL window. However, when ''VGL_SYNC'' is enabled,
+ the X11 Transport instead reuses the 3D application's X display
+ connection(s). Thus, enabling ''VGL_SYNC'' may prevent a 3D application
+ running with VirtualGL from exceeding the X server's connection limit if the
+ application opens an excessive number of OpenGL windows.
!!! If an image transport plugin is being used, then VirtualGL does not
automatically enable the X11 Transport or disable frame spoiling when
diff --git a/doc/index.html b/doc/index.html
index a708f881..fdc8570c 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -3,7 +3,7 @@
potentially dire effects on performance when used with a 2D X server on
a machine other than the VirtualGL server. It is strongly recommended
that VGL_SYNC be used only in conjunction with an X proxy
- running on the VirtualGL server.
+ running on the VirtualGL server.
In order to implement
+ frame spoiling, and also to allow the last frame to be transported while
+ the current frame is being rendered and read back, VirtualGL’s
+ built-in image transports use a separate “transport thread”.
+ To ensure thread safety, the X11 Transport normally creates multiple X
+ display connections for each OpenGL window. However, when
+ VGL_SYNC is enabled, the X11 Transport instead reuses the
+ 3D application’s X display connection(s). Thus, enabling
+ VGL_SYNC may prevent a 3D application running with
+ VirtualGL from exceeding the X server’s connection limit if the
+ application opens an excessive number of OpenGL windows.
If an image transport plugin is being used, then VirtualGL does not automatically enable the X11 Transport or disable frame spoiling when VGL_SYNC is set. This allows the plugin to handle synchronous image delivery as it sees fit (or to simply ignore this option.)
diff --git a/server/X11Trans.cpp b/server/X11Trans.cpp
index b7c826fd..4fe6ce3c 100644
--- a/server/X11Trans.cpp
+++ b/server/X11Trans.cpp
@@ -1,6 +1,6 @@
// Copyright (C)2004 Landmark Graphics Corporation
// Copyright (C)2005, 2006 Sun Microsystems, Inc.
-// Copyright (C)2010-2011, 2014, 2019-2021 D. R. Commander
+// Copyright (C)2010-2011, 2014, 2019-2021, 2024 D. R. Commander
//
// This library is free software and may be redistributed and/or modified under
// the terms of the wxWindows Library License, Version 3.1 or (at your option)
@@ -31,7 +31,8 @@ using namespace server;
X11Trans::X11Trans(void) : thread(NULL), deadYet(false)
{
- for(int i = 0; i < NFRAMES; i++) frames[i] = NULL;
+ if(fconfig.sync) nFrames = 1;
+ for(int i = 0; i < nFrames; i++) frames[i] = NULL;
thread = new Thread(this);
thread->start();
profBlit.setName("Blit ");
@@ -116,12 +117,12 @@ FBXFrame *X11Trans::getFrame(Display *dpy, Window win, int width, int height)
CriticalSection::SafeLock l(mutex);
int index = -1;
- for(int i = 0; i < NFRAMES; i++)
+ for(int i = 0; i < nFrames; i++)
if(!frames[i] || (frames[i] && frames[i]->isComplete()))
index = i;
if(index < 0) THROW("No free buffers in pool");
if(!frames[index])
- frames[index] = new FBXFrame(dpy, win);
+ frames[index] = new FBXFrame(dpy, win, NULL, fconfig.sync);
f = frames[index]; f->waitUntilComplete();
}
diff --git a/server/X11Trans.h b/server/X11Trans.h
index 1d100bf8..b3fab6b9 100644
--- a/server/X11Trans.h
+++ b/server/X11Trans.h
@@ -1,6 +1,6 @@
// Copyright (C)2004 Landmark Graphics Corporation
// Copyright (C)2005, 2006 Sun Microsystems, Inc.
-// Copyright (C)2010-2011, 2014, 2021 D. R. Commander
+// Copyright (C)2010-2011, 2014, 2021, 2024 D. R. Commander
//
// This library is free software and may be redistributed and/or modified under
// the terms of the wxWindows Library License, Version 3.1 or (at your option)
@@ -34,7 +34,7 @@ namespace server
deadYet = true;
q.release();
if(thread) { thread->stop(); delete thread; thread = NULL; }
- for(int i = 0; i < NFRAMES; i++)
+ for(int i = 0; i < nFrames; i++)
{
delete frames[i]; frames[i] = NULL;
}
@@ -49,9 +49,9 @@ namespace server
private:
- static const int NFRAMES = 3;
+ int nFrames = 3;
util::CriticalSection mutex;
- common::FBXFrame *frames[NFRAMES];
+ common::FBXFrame *frames[3];
util::Event ready;
util::GenericQ q;
util::Thread *thread;