Skip to content

Commit 930a7b3

Browse files
authored
[workspace] Load X11 lazily (#23604)
X11 is not loaded until the first time its needed. Rendering via EGL will not load it. (We still require X11 at build-time.)
1 parent 60337be commit 930a7b3

File tree

10 files changed

+123
-47
lines changed

10 files changed

+123
-47
lines changed

geometry/render_gl/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ drake_cc_library(
4646
] + select({
4747
"@drake//tools/skylark:linux": [
4848
"@vtk_internal//:vtkglad",
49-
"@x11",
49+
"@vtk_internal//:vtkx11",
5050
],
5151
"//conditions:default": [],
5252
}),

geometry/render_gl/internal_loaders.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <string>
66

77
#if !defined(__APPLE__)
8+
#include <vtkX11Functions.h>
89
#include <vtkglad/include/glad/egl.h>
910
#include <vtkglad/include/glad/glx.h>
1011
#endif
@@ -56,8 +57,9 @@ void* GladLoaderLoadGlx() {
5657
// exits (https://linux.die.net/man/3/xclosedisplay), but it seems not so
5758
// evil to skip that.
5859
static Display* g_display = []() {
59-
XInitThreads();
60-
Display* display = XOpenDisplay(0);
60+
vtkX11FunctionsInitialize();
61+
vtkXInitThreads();
62+
Display* display = vtkXOpenDisplay(0);
6163
if (display == nullptr) {
6264
const char* display_env = std::getenv("DISPLAY");
6365
throw std::logic_error(

geometry/render_gl/internal_opengl_context.cc

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
#include <string>
88
#include <utility>
99

10-
// Note: This is intentionally included here since it's only needed at the
10+
// Note: These are intentionally included here since they are only needed at the
1111
// implementation level, and not in a grouping of more generic headers like
1212
// opengl_includes.h. See opengl_context.h for where pimpl is applied.
13+
#include <vtkX11Functions.h>
1314
#include <vtkglad/include/glad/glx.h>
1415

1516
#include "drake/common/drake_assert.h"
@@ -119,7 +120,7 @@ class OpenGlContext::Impl {
119120
GLXFBConfig* fb_configs =
120121
glXChooseFBConfig(display(), screen_id, kVisualAttribs, &fb_count);
121122
ScopeExit guard([fb_configs]() {
122-
XFree(fb_configs);
123+
vtkXFree(fb_configs);
123124
});
124125
if (fb_configs == nullptr) {
125126
throw std::runtime_error(
@@ -139,7 +140,7 @@ class OpenGlContext::Impl {
139140
"unavailable.");
140141
}
141142
ScopeExit visual_guard([visual]() {
142-
XFree(visual);
143+
vtkXFree(visual);
143144
});
144145
XSetWindowAttributes window_attribs;
145146

@@ -149,23 +150,23 @@ class OpenGlContext::Impl {
149150
bool is_complete = false;
150151

151152
// This requires a call to XFreeColormap in the destructor.
152-
window_attribs.colormap = XCreateColormap(
153+
window_attribs.colormap = vtkXCreateColormap(
153154
display(), RootWindow(display(), screen_id), visual->visual, AllocNone);
154155
ScopeExit colormap_guard(
155156
[colormap = window_attribs.colormap, &is_complete]() {
156-
if (!is_complete) XFreeColormap(display(), colormap);
157+
if (!is_complete) vtkXFreeColormap(display(), colormap);
157158
});
158159

159160
// Enable just the Expose event so we know when the window is ready to be
160161
// redrawn.
161162
window_attribs.event_mask = ExposureMask;
162163
// This requires a call to XDestroyWindow in the destructor.
163-
window_ = XCreateWindow(display(), RootWindow(display(), screen_id), 0, 0,
164-
window_width_, window_height_, 0, visual->depth,
165-
InputOutput, visual->visual,
166-
CWColormap | CWEventMask, &window_attribs);
164+
window_ = vtkXCreateWindow(display(), RootWindow(display(), screen_id), 0,
165+
0, window_width_, window_height_, 0,
166+
visual->depth, InputOutput, visual->visual,
167+
CWColormap | CWEventMask, &window_attribs);
167168
ScopeExit window_guard([window = window_, &is_complete]() {
168-
if (!is_complete) XDestroyWindow(display(), window);
169+
if (!is_complete) vtkXDestroyWindow(display(), window);
169170
});
170171

171172
// Create an OpenGL context.
@@ -185,7 +186,7 @@ class OpenGlContext::Impl {
185186
if (!is_complete) glXDestroyContext(display(), context);
186187
});
187188

188-
XSync(display(), False);
189+
vtkXSync(display(), False);
189190

190191
// Enable debug.
191192
if (debug) {
@@ -205,9 +206,9 @@ class OpenGlContext::Impl {
205206
~Impl() {
206207
glXDestroyContext(display(), context_);
207208
XWindowAttributes window_attribs;
208-
XGetWindowAttributes(display(), window_, &window_attribs);
209-
XFreeColormap(display(), window_attribs.colormap);
210-
XDestroyWindow(display(), window_);
209+
vtkXGetWindowAttributes(display(), window_, &window_attribs);
210+
vtkXFreeColormap(display(), window_attribs.colormap);
211+
vtkXDestroyWindow(display(), window_);
211212
}
212213

213214
void MakeCurrent() const {
@@ -230,14 +231,14 @@ class OpenGlContext::Impl {
230231

231232
void DisplayWindow(const int width, const int height) {
232233
if (width != window_width_ || height != window_height_) {
233-
XResizeWindow(display(), window_, width, height);
234+
vtkXResizeWindow(display(), window_, width, height);
234235
// If the window isn't viewable, it won't send an expose event.
235236
if (IsWindowViewable()) WaitForExposeEvent();
236237
window_width_ = width;
237238
window_height_ = height;
238239
}
239240
if (!IsWindowViewable()) {
240-
XMapRaised(display(), window_);
241+
vtkXMapRaised(display(), window_);
241242
WaitForExposeEvent();
242243
}
243244
// We wait for confirmation events to make sure we don't attempt to draw
@@ -249,14 +250,14 @@ class OpenGlContext::Impl {
249250

250251
void HideWindow() {
251252
if (IsWindowViewable()) {
252-
XUnmapWindow(display(), window_);
253+
vtkXUnmapWindow(display(), window_);
253254
// Unmapping a window provides no events on that window.
254255
}
255256
}
256257

257258
bool IsWindowViewable() const {
258259
XWindowAttributes attr;
259-
const Status status = XGetWindowAttributes(display(), window_, &attr);
260+
const Status status = vtkXGetWindowAttributes(display(), window_, &attr);
260261

261262
// In xlib, a zero status implies function failure.
262263
// https://tronche.com/gui/x/xlib/introduction/errors.html#Status
@@ -269,15 +270,15 @@ class OpenGlContext::Impl {
269270
}
270271

271272
void UpdateWindow() {
272-
XClearWindow(display(), window_);
273+
vtkXClearWindow(display(), window_);
273274
glXSwapBuffers(display(), window_);
274275
}
275276

276277
// Waits for the display() to transmit an Expose event.
277278
void WaitForExposeEvent() const {
278279
XEvent event;
279280
// This blocks until the window gets an "Expose" event.
280-
XWindowEvent(display(), window_, ExposureMask, &event);
281+
vtkXWindowEvent(display(), window_, ExposureMask, &event);
281282
DRAKE_DEMAND(event.type == Expose);
282283
}
283284

geometry/render_vtk/BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ drake_cc_library(
6363
"//geometry/render_gl:internal_loaders",
6464
"@vtk_internal//:vtkRenderingCore",
6565
"@vtk_internal//:vtkRenderingOpenGL2",
66-
"@vtk_internal//:vtkglad",
6766
],
6867
)
6968

geometry/render_vtk/internal_make_render_window.cc

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ vtkSmartPointer<vtkRenderWindow> MakeRenderWindow(
4343
}
4444
case RenderEngineVtkBackend::kGlx: {
4545
#if !defined(__APPLE__)
46-
// Open the library at most once per process. This is important because
47-
// loading the library every time leaks resources ("too many clients")
48-
// that are in short supply when using a typical Xorg server.
49-
vtkX11FunctionsInitialize();
5046
Display* display =
5147
static_cast<Display*>(render_gl::internal::GladLoaderLoadGlx());
5248
DRAKE_DEMAND(display != nullptr);

tools/install/libdrake/BUILD.bazel

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -330,17 +330,6 @@ cc_library(
330330
}),
331331
)
332332

333-
# Depend on X11 iff on Ubuntu and not MacOS.
334-
cc_library(
335-
name = "x11_deps",
336-
deps = select({
337-
"//conditions:default": [
338-
"@x11",
339-
],
340-
"//tools/cc_toolchain:apple": [],
341-
}),
342-
)
343-
344333
# Provide a cc_library target that provides libdrake.so, its headers, its
345334
# header-only dependencies, and its required *.so's. This is aliased by
346335
# `//:drake_shared_library`, which is what downstream users will consume if
@@ -371,7 +360,6 @@ cc_library(
371360
deps = [
372361
":gurobi_deps",
373362
":mosek_deps",
374-
":x11_deps",
375363
"//common:drake_marker_shared_library",
376364
"//tools/workspace/fmt:shared_library_maybe",
377365
"//tools/workspace/lcm_internal:shared_library_maybe",
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
[vtk] Add more X11 function pointers
2+
3+
--- Utilities/X11/vtkX11Functions.cxx
4+
+++ Utilities/X11/vtkX11Functions.cxx
5+
@@ -79,6 +79,11 @@ DEFINE_POINTER_TO_FUNCTION(vtkXCreateWindow);
6+
DEFINE_POINTER_TO_FUNCTION(vtkXRootWindowOfScreen);
7+
DEFINE_POINTER_TO_FUNCTION(vtkXRootWindow);
8+
DEFINE_POINTER_TO_FUNCTION(vtkXGetVisualInfo);
9+
+DEFINE_POINTER_TO_FUNCTION(vtkXClearWindow);
10+
+DEFINE_POINTER_TO_FUNCTION(vtkXFreeColormap);
11+
+DEFINE_POINTER_TO_FUNCTION(vtkXInitThreads);
12+
+DEFINE_POINTER_TO_FUNCTION(vtkXMapRaised);
13+
+DEFINE_POINTER_TO_FUNCTION(vtkXWindowEvent);
14+
15+
// Xcursor API
16+
#if VTK_HAVE_XCURSOR
17+
@@ -167,6 +172,11 @@ extern "C"
18+
LOAD_POINTER_TO_FUNCTION(libX11, XRootWindowOfScreen, vtkXRootWindowOfScreen);
19+
LOAD_POINTER_TO_FUNCTION(libX11, XRootWindow, vtkXRootWindow);
20+
LOAD_POINTER_TO_FUNCTION(libX11, XGetVisualInfo, vtkXGetVisualInfo);
21+
+ LOAD_POINTER_TO_FUNCTION(libX11, XClearWindow, vtkXClearWindow);
22+
+ LOAD_POINTER_TO_FUNCTION(libX11, XFreeColormap, vtkXFreeColormap);
23+
+ LOAD_POINTER_TO_FUNCTION(libX11, XInitThreads, vtkXInitThreads);
24+
+ LOAD_POINTER_TO_FUNCTION(libX11, XMapRaised, vtkXMapRaised);
25+
+ LOAD_POINTER_TO_FUNCTION(libX11, XWindowEvent, vtkXWindowEvent);
26+
#if VTK_HAVE_XCURSOR
27+
libXcursor = dlopen("libXcursor.so", RTLD_LAZY | RTLD_GLOBAL);
28+
if (libXcursor == nullptr)
29+
@@ -245,6 +255,11 @@ extern "C"
30+
NULLIFY_POINTER_TO_FUNCTION(vtkXRootWindowOfScreen);
31+
NULLIFY_POINTER_TO_FUNCTION(vtkXRootWindow);
32+
NULLIFY_POINTER_TO_FUNCTION(vtkXGetVisualInfo);
33+
+ NULLIFY_POINTER_TO_FUNCTION(vtkXClearWindow);
34+
+ NULLIFY_POINTER_TO_FUNCTION(vtkXFreeColormap);
35+
+ NULLIFY_POINTER_TO_FUNCTION(vtkXInitThreads);
36+
+ NULLIFY_POINTER_TO_FUNCTION(vtkXMapRaised);
37+
+ NULLIFY_POINTER_TO_FUNCTION(vtkXWindowEvent);
38+
39+
// Xcursor API
40+
#if VTK_HAVE_XCURSOR
41+
42+
--- Utilities/X11/vtkX11Functions.h.in
43+
+++ Utilities/X11/vtkX11Functions.h.in
44+
@@ -111,6 +111,11 @@
45+
#define vtkXRootWindowOfScreen VTK_ABI_NAMESPACE_MANGLE(vtkXRootWindowOfScreen)
46+
#define vtkXRootWindow VTK_ABI_NAMESPACE_MANGLE(vtkXRootWindow)
47+
#define vtkXGetVisualInfo VTK_ABI_NAMESPACE_MANGLE(vtkXGetVisualInfo)
48+
+#define vtkXClearWindow VTK_ABI_NAMESPACE_MANGLE(vtkXClearWindow)
49+
+#define vtkXFreeColormap VTK_ABI_NAMESPACE_MANGLE(vtkXFreeColormap)
50+
+#define vtkXInitThreads VTK_ABI_NAMESPACE_MANGLE(vtkXInitThreads)
51+
+#define vtkXMapRaised VTK_ABI_NAMESPACE_MANGLE(vtkXMapRaised)
52+
+#define vtkXWindowEvent VTK_ABI_NAMESPACE_MANGLE(vtkXWindowEvent)
53+
54+
#if VTK_HAVE_XCURSOR
55+
#define vtkXcursorFilenameLoadCursor VTK_ABI_NAMESPACE_MANGLE(vtkXcursorFilenameLoadCursor)
56+
@@ -198,6 +203,11 @@ extern "C"
57+
typedef Window (*vtkXRootWindowOfScreenType)(Screen*);
58+
typedef Window (*vtkXRootWindowType)(Display*, int);
59+
typedef XVisualInfo* (*vtkXGetVisualInfoType)(Display*, long, XVisualInfo*, int*);
60+
+ typedef int (*vtkXClearWindowType)(Display*, Window);
61+
+ typedef Colormap (*vtkXFreeColormapType)(Display*, Window);
62+
+ typedef Status (*vtkXInitThreadsType)();
63+
+ typedef int (*vtkXMapRaisedType)(Display*, Window);
64+
+ typedef int (*vtkXWindowEventType)(Display*, Window, long, XEvent*);
65+
// Xcursor API
66+
#if VTK_HAVE_XCURSOR
67+
typedef Cursor (*vtkXcursorFilenameLoadCursorType)(Display*, const char*);
68+
@@ -263,6 +273,11 @@ extern "C"
69+
VTKX11_EXPORT extern vtkXRootWindowOfScreenType vtkXRootWindowOfScreen;
70+
VTKX11_EXPORT extern vtkXRootWindowType vtkXRootWindow;
71+
VTKX11_EXPORT extern vtkXGetVisualInfoType vtkXGetVisualInfo;
72+
+ VTKX11_EXPORT extern vtkXClearWindowType vtkXClearWindow;
73+
+ VTKX11_EXPORT extern vtkXFreeColormapType vtkXFreeColormap;
74+
+ VTKX11_EXPORT extern vtkXInitThreadsType vtkXInitThreads;
75+
+ VTKX11_EXPORT extern vtkXMapRaisedType vtkXMapRaised;
76+
+ VTKX11_EXPORT extern vtkXWindowEventType vtkXWindowEvent;
77+
// Xcursor API
78+
#if VTK_HAVE_XCURSOR
79+
VTKX11_EXPORT extern vtkXcursorFilenameLoadCursorType vtkXcursorFilenameLoadCursor;

tools/workspace/vtk_internal/repository.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ def vtk_internal_repository(
198198
":patches/upstream/common_core_rm_iostream.patch",
199199
":patches/upstream/rendering_core_vtkcomposite_exception.patch",
200200
":patches/upstream/rendering_opengl2_scaled_albedo_for_ibl.patch",
201+
":patches/upstream/utilities_x11_more_functions.patch",
201202
":patches/upstream/utilities_x11_vtk_cursor_guard.patch",
202203
":patches/upstream/vtkpugixml_global_ctor.patch",
203204
":patches/common_core_fmt12.patch",

tools/workspace/vtk_internal/settings.bzl

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ MODULE_SETTINGS = {
8080
}),
8181
},
8282
"VTK::x11": {
83+
"visibility": ["//visibility:public"],
8384
"cmake_defines": select({
8485
":osx": [],
8586
"//conditions:default": [
@@ -92,6 +93,15 @@ MODULE_SETTINGS = {
9293
],
9394
"//conditions:default": [],
9495
}),
96+
# Propagate X11 include dirs to dependents so that they can access X11
97+
# structs and definitions. This mimics `vtk_module_include(VTK::x11
98+
# INTERFACE ${X11_INCLUDE_DIR})` from upstream.
99+
"deps_extra": select({
100+
":osx": [],
101+
"//conditions:default": [
102+
"@drake//tools/workspace/x11:hdrs",
103+
],
104+
}),
95105
},
96106

97107
# Second, we'll configure the modules Drake needs (in alphabetical order).
@@ -558,13 +568,6 @@ MODULE_SETTINGS = {
558568
],
559569
"//conditions:default": [],
560570
}),
561-
"deps_extra": select({
562-
":osx": [],
563-
"//conditions:default": [
564-
# Mimic vtk_module_link(... X11::X11) from upstream.
565-
"@x11",
566-
],
567-
}),
568571
"module_deps_ignore": [
569572
"VTK::IOXML",
570573
"VTK::RenderingFreeType",

tools/workspace/x11/BUILD.bazel

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
load("//tools/install:install.bzl", "install")
22
load("//tools/lint:lint.bzl", "add_lint_tests")
3+
load("//tools/skylark:drake_cc.bzl", "cc_nolink_library")
34

45
# ---- Logic for choosing which x11 to use. ---
56

@@ -12,6 +13,12 @@ alias(
1213
visibility = ["//visibility:public"],
1314
)
1415

16+
cc_nolink_library(
17+
name = "hdrs",
18+
visibility = ["@vtk_internal//:__pkg__"],
19+
deps = ["@x11"],
20+
)
21+
1522
# ---- Logic for installing x11-related files. ---
1623

1724
install(

0 commit comments

Comments
 (0)