summarylogtreecommitdiffstats
path: root/0001-Avoid-calling-XOpenDisplay-multiple-times-fixes-cras.patch
diff options
context:
space:
mode:
authorSandy Carter2017-06-08 21:59:09 -0400
committerSandy Carter2017-06-08 21:59:09 -0400
commitf07a09f6c31dca53cf7cd01a8a048c217525a8e3 (patch)
tree9b23fefa43180b832e3a1b910014ea40a6570f21 /0001-Avoid-calling-XOpenDisplay-multiple-times-fixes-cras.patch
parentf94c34f6e88c0a3a005b1b8a2af16c70bc8796f9 (diff)
downloadaur-f07a09f6c31dca53cf7cd01a8a048c217525a8e3.tar.gz
Add X display patch
Diffstat (limited to '0001-Avoid-calling-XOpenDisplay-multiple-times-fixes-cras.patch')
-rw-r--r--0001-Avoid-calling-XOpenDisplay-multiple-times-fixes-cras.patch814
1 files changed, 814 insertions, 0 deletions
diff --git a/0001-Avoid-calling-XOpenDisplay-multiple-times-fixes-cras.patch b/0001-Avoid-calling-XOpenDisplay-multiple-times-fixes-cras.patch
new file mode 100644
index 00000000000..b37e9fc4f9a
--- /dev/null
+++ b/0001-Avoid-calling-XOpenDisplay-multiple-times-fixes-cras.patch
@@ -0,0 +1,814 @@
+From 3ab7510c7f4695afa1a21426f791de288329878d Mon Sep 17 00:00:00 2001
+From: baldurk <baldurk@baldurk.org>
+Date: Tue, 30 May 2017 12:02:00 +0100
+Subject: [PATCH] Avoid calling XOpenDisplay multiple times, fixes crashes on
+ Intel Mesa
+
+* See https://bugs.freedesktop.org/show_bug.cgi?id=99831
+ https://bugs.freedesktop.org/show_bug.cgi?id=54971
+* It's not clear if it's invalid to call XOpenDisplay more than once but
+ at the very least it's only really used as convenience to avoid
+ plumbing the display handle through.
+---
+ qrenderdoc/Code/qrenderdoc.cpp | 9 +++++
+ renderdoc/api/replay/renderdoc_replay.h | 16 ++++++++
+ renderdoc/core/core.cpp | 21 +++++++++++
+ renderdoc/core/core.h | 5 +++
+ renderdoc/driver/gl/gl_hooks_egl.cpp | 10 +----
+ renderdoc/driver/gl/gl_hooks_linux.cpp | 6 +--
+ renderdoc/driver/gl/gl_replay_egl.cpp | 22 -----------
+ renderdoc/driver/gl/gl_replay_linux.cpp | 8 +---
+ renderdoc/replay/entry_points.cpp | 11 ++++++
+ renderdoccmd/renderdoccmd.cpp | 66 +++++++++++++++++++++++++--------
+ renderdoccmd/renderdoccmd.h | 12 +++---
+ renderdoccmd/renderdoccmd_android.cpp | 3 +-
+ renderdoccmd/renderdoccmd_apple.cpp | 3 +-
+ renderdoccmd/renderdoccmd_linux.cpp | 27 ++++++++------
+ renderdoccmd/renderdoccmd_win32.cpp | 14 ++++---
+ 15 files changed, 150 insertions(+), 83 deletions(-)
+
+diff --git a/qrenderdoc/Code/qrenderdoc.cpp b/qrenderdoc/Code/qrenderdoc.cpp
+index e1bfebf8..8c168c45 100644
+--- a/qrenderdoc/Code/qrenderdoc.cpp
++++ b/qrenderdoc/Code/qrenderdoc.cpp
+@@ -182,6 +182,15 @@ int main(int argc, char *argv[])
+ GUIInvoke::init();
+
+ PythonContext::GlobalInit();
++
++ {
++ GlobalEnvironment env;
++#if defined(RENDERDOC_PLATFORM_LINUX)
++ env.xlibDisplay = QX11Info::display();
++#endif
++ RENDERDOC_InitGlobalEnv(env, rdctype::array<rdctype::str>());
++ }
++
+ {
+ CaptureContext ctx(filename, remoteHost, remoteIdent, temp, config);
+
+diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h
+index c60a545c..36260fca 100644
+--- a/renderdoc/api/replay/renderdoc_replay.h
++++ b/renderdoc/api/replay/renderdoc_replay.h
+@@ -25,6 +25,7 @@
+
+ #pragma once
+
++#include <stddef.h>
+ #include <stdint.h>
+
+ template <typename T>
+@@ -115,6 +116,10 @@ struct XlibWindowData
+ Drawable window;
+ };
+
++#else
++
++typedef void *Display;
++
+ #endif
+
+ #if defined(RENDERDOC_WINDOWING_XCB)
+@@ -167,6 +172,13 @@ enum class WindowingSystem : uint32_t
+ Android,
+ };
+
++DOCUMENT(R"(Internal structure used for initialising environment in a replay application.)");
++struct GlobalEnvironment
++{
++ DOCUMENT("The handle to the X display to use internally. If left ``NULL``, one will be opened.");
++ Display *xlibDisplay = NULL;
++};
++
+ // needs to be declared up here for reference in basic_types
+
+ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_FreeArrayMem(const void *mem);
+@@ -1367,6 +1379,10 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_UpdateVulkanLayerRegistrati
+ // Miscellaneous!
+ //////////////////////////////////////////////////////////////////////////
+
++DOCUMENT("Internal function for initialising global process environment in a replay program.");
++extern "C" RENDERDOC_API void RENDERDOC_CC
++RENDERDOC_InitGlobalEnv(GlobalEnvironment env, const rdctype::array<rdctype::str> &args);
++
+ DOCUMENT("Internal function for triggering exception handler.");
+ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_TriggerExceptionHandler(void *exceptionPtrs,
+ bool32 crashed);
+diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp
+index 83b855ab..da9dda75 100644
+--- a/renderdoc/core/core.cpp
++++ b/renderdoc/core/core.cpp
+@@ -36,6 +36,10 @@
+ #include "stb/stb_image.h"
+ #include "crash_handler.h"
+
++#if ENABLED(RDOC_LINUX) && ENABLED(RDOC_XLIB)
++#include <X11/Xlib.h>
++#endif
++
+ // from image_viewer.cpp
+ ReplayStatus IMG_CreateReplayDevice(const char *logfile, IReplayDriver **driver);
+
+@@ -404,6 +408,23 @@ void RenderDoc::Shutdown()
+ }
+ }
+
++void RenderDoc::ProcessGlobalEnvironment(GlobalEnvironment env, const std::vector<std::string> &args)
++{
++ m_GlobalEnv = env;
++
++#if ENABLED(RDOC_LINUX) && ENABLED(RDOC_XLIB)
++ if(!m_GlobalEnv.xlibDisplay)
++ m_GlobalEnv.xlibDisplay = XOpenDisplay(NULL);
++#endif
++
++ if(!args.empty())
++ {
++ RDCDEBUG("Replay application launched with parameters:");
++ for(size_t i = 0; i < args.size(); i++)
++ RDCDEBUG("[%u]: %s", (uint32_t)i, args[i].c_str());
++ }
++}
++
+ bool RenderDoc::MatchClosestWindow(void *&dev, void *&wnd)
+ {
+ DeviceWnd dw(dev, wnd);
+diff --git a/renderdoc/core/core.h b/renderdoc/core/core.h
+index cbb33521..1752f875 100644
+--- a/renderdoc/core/core.h
++++ b/renderdoc/core/core.h
+@@ -205,6 +205,9 @@ public:
+ void Initialise();
+ void Shutdown();
+
++ const GlobalEnvironment GetGlobalEnvironment() { return m_GlobalEnv; }
++ void ProcessGlobalEnvironment(GlobalEnvironment env, const std::vector<std::string> &args);
++
+ void RegisterShutdownFunction(ShutdownFunction func) { m_ShutdownFunctions.insert(func); }
+ void SetReplayApp(bool replay) { m_Replay = replay; }
+ bool IsReplayApp() const { return m_Replay; }
+@@ -350,6 +353,8 @@ private:
+ vector<RENDERDOC_InputButton> m_FocusKeys;
+ vector<RENDERDOC_InputButton> m_CaptureKeys;
+
++ GlobalEnvironment m_GlobalEnv;
++
+ FrameTimer m_FrameTimer;
+
+ string m_LoggingFilename;
+diff --git a/renderdoc/driver/gl/gl_hooks_egl.cpp b/renderdoc/driver/gl/gl_hooks_egl.cpp
+index 4dd147a0..bc5cf90d 100644
+--- a/renderdoc/driver/gl/gl_hooks_egl.cpp
++++ b/renderdoc/driver/gl/gl_hooks_egl.cpp
+@@ -215,15 +215,9 @@ public:
+ break;
+ }
+ #endif
+- case WindowingSystem::Unknown: {
+-#if ENABLED(RDOC_LINUX)
+- // allow undefined so that internally we can create a window-less context
+- Display *dpy = XOpenDisplay(NULL);
+- if(dpy == NULL)
+- return ret;
+-#endif
++ case WindowingSystem::Unknown:
++ // allow WindowingSystem::Unknown so that internally we can create a window-less context
+ break;
+- }
+ default: RDCERR("Unexpected window system %u", system); break;
+ }
+
+diff --git a/renderdoc/driver/gl/gl_hooks_linux.cpp b/renderdoc/driver/gl/gl_hooks_linux.cpp
+index 4a50f742..445d6916 100644
+--- a/renderdoc/driver/gl/gl_hooks_linux.cpp
++++ b/renderdoc/driver/gl/gl_hooks_linux.cpp
+@@ -241,8 +241,8 @@ public:
+ }
+ else if(system == WindowingSystem::Unknown)
+ {
+- // allow undefined so that internally we can create a window-less context
+- dpy = XOpenDisplay(NULL);
++ // allow WindowingSystem::Unknown so that internally we can create a window-less context
++ dpy = RenderDoc::Inst().GetGlobalEnvironment().xlibDisplay;
+
+ if(dpy == NULL)
+ return ret;
+@@ -276,7 +276,6 @@ public:
+
+ if(fbcfg == NULL)
+ {
+- XCloseDisplay(dpy);
+ RDCERR("Couldn't choose default framebuffer config");
+ return ret;
+ }
+@@ -317,7 +316,6 @@ public:
+
+ if(ctx == NULL)
+ {
+- XCloseDisplay(dpy);
+ RDCERR("Couldn't create %d.%d context - something changed since creation", GLCoreVersion / 10,
+ GLCoreVersion % 10);
+ return ret;
+diff --git a/renderdoc/driver/gl/gl_replay_egl.cpp b/renderdoc/driver/gl/gl_replay_egl.cpp
+index eaad0fef..beabeef9 100644
+--- a/renderdoc/driver/gl/gl_replay_egl.cpp
++++ b/renderdoc/driver/gl/gl_replay_egl.cpp
+@@ -117,16 +117,6 @@ ReplayStatus GLES_CreateReplayDevice(const char *logfile, IReplayDriver **driver
+ initParams.isSRGB = 0;
+ #endif
+
+-#if DISABLED(RDOC_ANDROID)
+- Display *dpy = XOpenDisplay(NULL);
+-
+- if(dpy == NULL)
+- {
+- RDCERR("Couldn't open default X display");
+- return ReplayStatus::APIInitFailed;
+- }
+-#endif
+-
+ eglBindAPIProc(EGL_OPENGL_ES_API);
+
+ EGLDisplay eglDisplay = eglGetDisplayProc(EGL_DEFAULT_DISPLAY);
+@@ -167,9 +157,6 @@ ReplayStatus GLES_CreateReplayDevice(const char *logfile, IReplayDriver **driver
+ EGLContext ctx = eglCreateContextProc(eglDisplay, config, EGL_NO_CONTEXT, ctxAttribs);
+ if(ctx == NULL)
+ {
+-#if DISABLED(RDOC_ANDROID)
+- XCloseDisplay(dpy);
+-#endif
+ GLReplay::PostContextShutdownCounters();
+ RDCERR("Couldn't create GL ES 3.x context - RenderDoc requires OpenGL ES 3.x availability");
+ return ReplayStatus::APIHardwareUnsupported;
+@@ -182,9 +169,6 @@ ReplayStatus GLES_CreateReplayDevice(const char *logfile, IReplayDriver **driver
+ {
+ RDCERR("Couldn't create a suitable PBuffer");
+ eglDestroySurfaceProc(eglDisplay, pbuffer);
+-#if DISABLED(RDOC_ANDROID)
+- XCloseDisplay(dpy);
+-#endif
+ GLReplay::PostContextShutdownCounters();
+ return ReplayStatus::APIInitFailed;
+ }
+@@ -195,9 +179,6 @@ ReplayStatus GLES_CreateReplayDevice(const char *logfile, IReplayDriver **driver
+ RDCERR("Couldn't active the created GL ES context");
+ eglDestroySurfaceProc(eglDisplay, pbuffer);
+ eglDestroyContextProc(eglDisplay, ctx);
+-#if DISABLED(RDOC_ANDROID)
+- XCloseDisplay(dpy);
+-#endif
+ GLReplay::PostContextShutdownCounters();
+ return ReplayStatus::APIInitFailed;
+ }
+@@ -210,9 +191,6 @@ ReplayStatus GLES_CreateReplayDevice(const char *logfile, IReplayDriver **driver
+ {
+ eglDestroySurfaceProc(eglDisplay, pbuffer);
+ eglDestroyContextProc(eglDisplay, ctx);
+-#if DISABLED(RDOC_ANDROID)
+- XCloseDisplay(dpy);
+-#endif
+ GLReplay::PostContextShutdownCounters();
+ return ReplayStatus::APIHardwareUnsupported;
+ }
+diff --git a/renderdoc/driver/gl/gl_replay_linux.cpp b/renderdoc/driver/gl/gl_replay_linux.cpp
+index 1070f85f..fef9a3b8 100644
+--- a/renderdoc/driver/gl/gl_replay_linux.cpp
++++ b/renderdoc/driver/gl/gl_replay_linux.cpp
+@@ -122,7 +122,7 @@ ReplayStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
+ attribs[i++] = GLX_CONTEXT_PROFILE_MASK_ARB;
+ attribs[i++] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
+
+- Display *dpy = XOpenDisplay(NULL);
++ Display *dpy = RenderDoc::Inst().GetGlobalEnvironment().xlibDisplay;
+
+ if(dpy == NULL)
+ {
+@@ -138,7 +138,6 @@ ReplayStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
+
+ if(fbcfg == NULL)
+ {
+- XCloseDisplay(dpy);
+ GLReplay::PostContextShutdownCounters();
+ RDCERR("Couldn't choose default framebuffer config");
+ return ReplayStatus::APIInitFailed;
+@@ -177,7 +176,6 @@ ReplayStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
+ if(ctx == NULL || X11ErrorSeen)
+ {
+ XFree(fbcfg);
+- XCloseDisplay(dpy);
+ GLReplay::PostContextShutdownCounters();
+ RDCERR("Couldn't create 3.2 context - RenderDoc requires OpenGL 3.2 availability");
+ return ReplayStatus::APIHardwareUnsupported;
+@@ -199,7 +197,6 @@ ReplayStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
+ glXDestroyPbufferProc(dpy, pbuffer);
+ glXDestroyCtxProc(dpy, ctx);
+ XFree(fbcfg);
+- XCloseDisplay(dpy);
+ GLReplay::PostContextShutdownCounters();
+ RDCERR("Couldn't make pbuffer & context current");
+ return ReplayStatus::APIInitFailed;
+@@ -218,7 +215,6 @@ ReplayStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
+ glXDestroyPbufferProc(dpy, pbuffer);
+ glXDestroyCtxProc(dpy, ctx);
+ XFree(fbcfg);
+- XCloseDisplay(dpy);
+ GLReplay::PostContextShutdownCounters();
+ return ReplayStatus::APIInitFailed;
+ }
+@@ -233,7 +229,6 @@ ReplayStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
+ glXDestroyPbufferProc(dpy, pbuffer);
+ glXDestroyCtxProc(dpy, ctx);
+ XFree(fbcfg);
+- XCloseDisplay(dpy);
+ GLReplay::PostContextShutdownCounters();
+ return ReplayStatus::APIHardwareUnsupported;
+ }
+@@ -245,7 +240,6 @@ ReplayStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
+ glXDestroyPbufferProc(dpy, pbuffer);
+ glXDestroyCtxProc(dpy, ctx);
+ XFree(fbcfg);
+- XCloseDisplay(dpy);
+ GLReplay::PostContextShutdownCounters();
+ return ReplayStatus::APIHardwareUnsupported;
+ }
+diff --git a/renderdoc/replay/entry_points.cpp b/renderdoc/replay/entry_points.cpp
+index 0999f721..23d7dbd9 100644
+--- a/renderdoc/replay/entry_points.cpp
++++ b/renderdoc/replay/entry_points.cpp
+@@ -300,6 +300,17 @@ extern "C" RENDERDOC_API const char *RENDERDOC_CC RENDERDOC_GetLogFile()
+ return RDCGETLOGFILE();
+ }
+
++extern "C" RENDERDOC_API void RENDERDOC_CC
++RENDERDOC_InitGlobalEnv(GlobalEnvironment env, const rdctype::array<rdctype::str> &args)
++{
++ std::vector<std::string> argsVec;
++ argsVec.reserve(args.size());
++ for(const rdctype::str &a : args)
++ argsVec.push_back(a.c_str());
++
++ RenderDoc::Inst().ProcessGlobalEnvironment(env, argsVec);
++}
++
+ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_TriggerExceptionHandler(void *exceptionPtrs,
+ bool32 crashed)
+ {
+diff --git a/renderdoccmd/renderdoccmd.cpp b/renderdoccmd/renderdoccmd.cpp
+index 72125a4e..d3727bb8 100644
+--- a/renderdoccmd/renderdoccmd.cpp
++++ b/renderdoccmd/renderdoccmd.cpp
+@@ -25,7 +25,6 @@
+
+ #include "renderdoccmd.h"
+ #include <app/renderdoc_app.h>
+-#include <replay/renderdoc_replay.h>
+ #include <replay/version.h>
+ #include <string>
+
+@@ -35,6 +34,15 @@ using std::wstring;
+ bool usingKillSignal = false;
+ volatile uint32_t killSignal = false;
+
++rdctype::array<rdctype::str> convertArgs(const std::vector<std::string> &args)
++{
++ rdctype::array<rdctype::str> ret;
++ ret.create((int)args.size());
++ for(size_t i = 0; i < args.size(); i++)
++ ret[i] = args[i];
++ return ret;
++}
++
+ void readCapOpts(const std::string &str, CaptureOptions *opts)
+ {
+ if(str.length() < sizeof(CaptureOptions))
+@@ -157,6 +165,7 @@ static std::vector<std::string> version_lines;
+
+ struct VersionCommand : public Command
+ {
++ VersionCommand(const GlobalEnvironment &env) : Command(env) {}
+ virtual void AddOptions(cmdline::parser &parser) {}
+ virtual const char *Description() { return "Print version information"; }
+ virtual bool IsInternalOnly() { return false; }
+@@ -187,6 +196,7 @@ void add_version_line(const std::string &str)
+
+ struct HelpCommand : public Command
+ {
++ HelpCommand(const GlobalEnvironment &env) : Command(env) {}
+ virtual void AddOptions(cmdline::parser &parser) {}
+ virtual const char *Description() { return "Print this help message"; }
+ virtual bool IsInternalOnly() { return false; }
+@@ -200,6 +210,7 @@ struct HelpCommand : public Command
+
+ struct ThumbCommand : public Command
+ {
++ ThumbCommand(const GlobalEnvironment &env) : Command(env) {}
+ virtual void AddOptions(cmdline::parser &parser)
+ {
+ parser.set_footer("<filename.rdc>");
+@@ -216,7 +227,8 @@ struct ThumbCommand : public Command
+ virtual bool IsCaptureCommand() { return false; }
+ virtual int Execute(cmdline::parser &parser, const CaptureOptions &)
+ {
+- if(parser.rest().empty())
++ std::vector<std::string> rest = parser.rest();
++ if(rest.empty())
+ {
+ std::cerr << "Error: thumb command requires a capture filename." << std::endl
+ << std::endl
+@@ -224,7 +236,11 @@ struct ThumbCommand : public Command
+ return 0;
+ }
+
+- string filename = parser.rest()[0];
++ string filename = rest[0];
++
++ rest.erase(rest.begin());
++
++ RENDERDOC_InitGlobalEnv(m_Env, convertArgs(rest));
+
+ string outfile = parser.get<string>("out");
+
+@@ -299,6 +315,7 @@ struct ThumbCommand : public Command
+
+ struct CaptureCommand : public Command
+ {
++ CaptureCommand(const GlobalEnvironment &env) : Command(env) {}
+ virtual void AddOptions(cmdline::parser &parser)
+ {
+ parser.set_footer("<executable> [program arguments]");
+@@ -330,6 +347,8 @@ struct CaptureCommand : public Command
+ cmdLine += EscapeArgument(parser.rest()[i]);
+ }
+
++ RENDERDOC_InitGlobalEnv(m_Env, rdctype::array<rdctype::str>());
++
+ std::cout << "Launching '" << executable << "'";
+
+ if(!cmdLine.empty())
+@@ -386,6 +405,7 @@ struct CaptureCommand : public Command
+
+ struct InjectCommand : public Command
+ {
++ InjectCommand(const GlobalEnvironment &env) : Command(env) {}
+ virtual void AddOptions(cmdline::parser &parser)
+ {
+ parser.add<uint32_t>("PID", 0, "The process ID of the process to inject.", true);
+@@ -403,6 +423,8 @@ struct InjectCommand : public Command
+
+ rdctype::array<EnvironmentModification> env;
+
++ RENDERDOC_InitGlobalEnv(m_Env, convertArgs(parser.rest()));
++
+ uint32_t ident = RENDERDOC_InjectIntoProcess(PID, env, logFile.empty() ? "" : logFile.c_str(),
+ opts, parser.exist("wait-for-exit"));
+
+@@ -428,6 +450,7 @@ struct InjectCommand : public Command
+
+ struct RemoteServerCommand : public Command
+ {
++ RemoteServerCommand(const GlobalEnvironment &env) : Command(env) {}
+ virtual void AddOptions(cmdline::parser &parser)
+ {
+ parser.add("daemon", 'd', "Go into the background.");
+@@ -447,6 +470,8 @@ struct RemoteServerCommand : public Command
+ string host = parser.get<string>("host");
+ uint32_t port = parser.get<uint32_t>("port");
+
++ RENDERDOC_InitGlobalEnv(m_Env, convertArgs(parser.rest()));
++
+ std::cerr << "Spawning a replay host listening on " << (host.empty() ? "*" : host) << ":"
+ << port << "..." << std::endl;
+
+@@ -468,6 +493,7 @@ struct RemoteServerCommand : public Command
+
+ struct ReplayCommand : public Command
+ {
++ ReplayCommand(const GlobalEnvironment &env) : Command(env) {}
+ virtual void AddOptions(cmdline::parser &parser)
+ {
+ parser.set_footer("<capture.rdc>");
+@@ -486,7 +512,8 @@ struct ReplayCommand : public Command
+ virtual bool IsCaptureCommand() { return false; }
+ virtual int Execute(cmdline::parser &parser, const CaptureOptions &)
+ {
+- if(parser.rest().empty())
++ std::vector<std::string> rest = parser.rest();
++ if(rest.empty())
+ {
+ std::cerr << "Error: capture command requires a filename to load." << std::endl
+ << std::endl
+@@ -494,7 +521,11 @@ struct ReplayCommand : public Command
+ return 0;
+ }
+
+- string filename = parser.rest()[0];
++ string filename = rest[0];
++
++ rest.erase(rest.begin());
++
++ RENDERDOC_InitGlobalEnv(m_Env, convertArgs(rest));
+
+ if(parser.exist("remote-host"))
+ {
+@@ -572,6 +603,7 @@ struct ReplayCommand : public Command
+
+ struct CapAltBitCommand : public Command
+ {
++ CapAltBitCommand(const GlobalEnvironment &env) : Command(env) {}
+ virtual void AddOptions(cmdline::parser &parser)
+ {
+ parser.add<uint32_t>("pid", 0, "");
+@@ -588,6 +620,8 @@ struct CapAltBitCommand : public Command
+ CaptureOptions cmdopts;
+ readCapOpts(parser.get<string>("capopts").c_str(), &cmdopts);
+
++ RENDERDOC_InitGlobalEnv(m_Env, rdctype::array<rdctype::str>());
++
+ std::vector<std::string> rest = parser.rest();
+
+ if(rest.size() % 3 != 0)
+@@ -673,12 +707,12 @@ struct CapAltBitCommand : public Command
+ }
+ };
+
+-int renderdoccmd(std::vector<std::string> &argv)
++int renderdoccmd(const GlobalEnvironment &env, std::vector<std::string> &argv)
+ {
+ try
+ {
+ // add basic commands, and common aliases
+- add_command("version", new VersionCommand());
++ add_command("version", new VersionCommand(env));
+
+ add_alias("--version", "version");
+ add_alias("-v", "version");
+@@ -686,7 +720,7 @@ int renderdoccmd(std::vector<std::string> &argv)
+ add_alias("/version", "version");
+ add_alias("/v", "version");
+
+- add_command("help", new HelpCommand());
++ add_command("help", new HelpCommand(env));
+
+ add_alias("--help", "help");
+ add_alias("-h", "help");
+@@ -698,12 +732,12 @@ int renderdoccmd(std::vector<std::string> &argv)
+ add_alias("/?", "help");
+
+ // add platform agnostic commands
+- add_command("thumb", new ThumbCommand());
+- add_command("capture", new CaptureCommand());
+- add_command("inject", new InjectCommand());
+- add_command("remoteserver", new RemoteServerCommand());
+- add_command("replay", new ReplayCommand());
+- add_command("capaltbit", new CapAltBitCommand());
++ add_command("thumb", new ThumbCommand(env));
++ add_command("capture", new CaptureCommand(env));
++ add_command("inject", new InjectCommand(env));
++ add_command("remoteserver", new RemoteServerCommand(env));
++ add_command("replay", new ReplayCommand(env));
++ add_command("capaltbit", new CapAltBitCommand(env));
+
+ if(argv.size() <= 1)
+ {
+@@ -833,12 +867,12 @@ int renderdoccmd(std::vector<std::string> &argv)
+ }
+ }
+
+-int renderdoccmd(int argc, char **c_argv)
++int renderdoccmd(const GlobalEnvironment &env, int argc, char **c_argv)
+ {
+ std::vector<std::string> argv;
+ argv.resize(argc);
+ for(int i = 0; i < argc; i++)
+ argv[i] = c_argv[i];
+
+- return renderdoccmd(argv);
++ return renderdoccmd(env, argv);
+ }
+diff --git a/renderdoccmd/renderdoccmd.h b/renderdoccmd/renderdoccmd.h
+index 9cd57887..59acb01f 100644
+--- a/renderdoccmd/renderdoccmd.h
++++ b/renderdoccmd/renderdoccmd.h
+@@ -24,14 +24,12 @@
+
+ #pragma once
+
++#include <replay/renderdoc_replay.h>
+ #include "3rdparty/cmdline/cmdline.h"
+
+-struct CaptureOptions;
+-struct TextureDisplay;
+-struct IReplayController;
+-
+ struct Command
+ {
++ Command(const GlobalEnvironment &env) { m_Env = env; }
+ virtual ~Command() {}
+ virtual void AddOptions(cmdline::parser &parser) = 0;
+ virtual int Execute(cmdline::parser &parser, const CaptureOptions &opts) = 0;
+@@ -39,6 +37,8 @@ struct Command
+
+ virtual bool IsInternalOnly() = 0;
+ virtual bool IsCaptureCommand() = 0;
++
++ GlobalEnvironment m_Env;
+ };
+
+ extern bool usingKillSignal;
+@@ -49,8 +49,8 @@ void add_version_line(const std::string &str);
+ void add_command(const std::string &name, Command *cmd);
+ void add_alias(const std::string &alias, const std::string &command);
+
+-int renderdoccmd(int argc, char **argv);
+-int renderdoccmd(std::vector<std::string> &argv);
++int renderdoccmd(const GlobalEnvironment &env, int argc, char **argv);
++int renderdoccmd(const GlobalEnvironment &env, std::vector<std::string> &argv);
+
+ void readCapOpts(const std::string &str, CaptureOptions *opts);
+
+diff --git a/renderdoccmd/renderdoccmd_android.cpp b/renderdoccmd/renderdoccmd_android.cpp
+index e427b314..10f99aa9 100644
+--- a/renderdoccmd/renderdoccmd_android.cpp
++++ b/renderdoccmd/renderdoccmd_android.cpp
+@@ -24,7 +24,6 @@
+
+ #include "renderdoccmd.h"
+ #include <locale.h>
+-#include <replay/renderdoc_replay.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <string>
+@@ -116,7 +115,7 @@ void handle_cmd(android_app *app, int32_t cmd)
+ vector<string> args = getRenderdoccmdArgs();
+ if(!args.size())
+ break; // Nothing for APK to do.
+- renderdoccmd(args);
++ renderdoccmd(GlobalEnvironment(), args);
+ break;
+ }
+ case APP_CMD_TERM_WINDOW: break;
+diff --git a/renderdoccmd/renderdoccmd_apple.cpp b/renderdoccmd/renderdoccmd_apple.cpp
+index 5a123ca5..3e5e0478 100644
+--- a/renderdoccmd/renderdoccmd_apple.cpp
++++ b/renderdoccmd/renderdoccmd_apple.cpp
+@@ -24,7 +24,6 @@
+
+ #include "renderdoccmd.h"
+ #include <locale.h>
+-#include <replay/renderdoc_replay.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <string>
+@@ -48,5 +47,5 @@ int main(int argc, char *argv[])
+
+ // process any apple-specific arguments here
+
+- return renderdoccmd(argc, argv);
++ return renderdoccmd(GlobalEnvironment(), argc, argv);
+ }
+diff --git a/renderdoccmd/renderdoccmd_linux.cpp b/renderdoccmd/renderdoccmd_linux.cpp
+index 4be601c5..99a129cc 100644
+--- a/renderdoccmd/renderdoccmd_linux.cpp
++++ b/renderdoccmd/renderdoccmd_linux.cpp
+@@ -53,7 +53,7 @@ void Daemonise()
+
+ struct VulkanRegisterCommand : public Command
+ {
+- VulkanRegisterCommand() {}
++ VulkanRegisterCommand(const GlobalEnvironment &env) : Command(env) {}
+ virtual void AddOptions(cmdline::parser &parser)
+ {
+ parser.add("ignore", 'i', "Do nothing and don't warn about Vulkan layer issues.");
+@@ -105,7 +105,7 @@ struct VulkanRegisterCommand : public Command
+ }
+ };
+
+-void VerifyVulkanLayer(int argc, char *argv[])
++void VerifyVulkanLayer(const GlobalEnvironment &env, int argc, char *argv[])
+ {
+ VulkanLayerFlags flags = VulkanLayerFlags::NoFlags;
+ rdctype::array<rdctype::str> myJSONs;
+@@ -116,7 +116,7 @@ void VerifyVulkanLayer(int argc, char *argv[])
+ if(!needUpdate)
+ {
+ if(!(flags & VulkanLayerFlags::Unfixable))
+- add_command("vulkanregister", new VulkanRegisterCommand());
++ add_command("vulkanregister", new VulkanRegisterCommand(env));
+ return;
+ }
+
+@@ -197,9 +197,11 @@ void VerifyVulkanLayer(int argc, char *argv[])
+ << std::endl;
+ std::cerr << std::endl;
+
+- add_command("vulkanregister", new VulkanRegisterCommand());
++ add_command("vulkanregister", new VulkanRegisterCommand(env));
+ }
+
++static Display *display = NULL;
++
+ void DisplayRendererPreview(IReplayController *renderer, TextureDisplay &displayCfg, uint32_t width,
+ uint32_t height)
+ {
+@@ -210,11 +212,6 @@ void DisplayRendererPreview(IReplayController *renderer, TextureDisplay &display
+ // need to create a hybrid setup xlib and xcb in case only one or the other is supported.
+ // We'll prefer xcb
+
+- // call XInitThreads - although we don't use xlib concurrently the driver might need to.
+- XInitThreads();
+-
+- Display *display = XOpenDisplay(NULL);
+-
+ if(display == NULL)
+ {
+ std::cerr << "Couldn't open X Display" << std::endl;
+@@ -373,8 +370,16 @@ int main(int argc, char *argv[])
+ signal(SIGINT, sig_handler);
+ signal(SIGTERM, sig_handler);
+
++ GlobalEnvironment env;
++
++ // call XInitThreads - although we don't use xlib concurrently the driver might need to.
++ XInitThreads();
++
++ // we don't check if display successfully opened, it's only a problem if it's needed later.
++ display = env.xlibDisplay = XOpenDisplay(NULL);
++
+ #if defined(RENDERDOC_SUPPORT_VULKAN)
+- VerifyVulkanLayer(argc, argv);
++ VerifyVulkanLayer(env, argc, argv);
+ #endif
+
+ // add compiled-in support to version line
+@@ -444,5 +449,5 @@ int main(int argc, char *argv[])
+ add_version_line(support);
+ }
+
+- return renderdoccmd(argc, argv);
++ return renderdoccmd(env, argc, argv);
+ }
+diff --git a/renderdoccmd/renderdoccmd_win32.cpp b/renderdoccmd/renderdoccmd_win32.cpp
+index 34f54a7a..a8bc510e 100644
+--- a/renderdoccmd/renderdoccmd_win32.cpp
++++ b/renderdoccmd/renderdoccmd_win32.cpp
+@@ -26,7 +26,6 @@
+ #include "renderdoccmd.h"
+ #include <app/renderdoc_app.h>
+ #include <renderdocshim.h>
+-#include <replay/renderdoc_replay.h>
+ #include <windows.h>
+ #include <string>
+ #include <vector>
+@@ -281,6 +280,7 @@ void DisplayRendererPreview(IReplayController *renderer, TextureDisplay &display
+
+ struct UpgradeCommand : public Command
+ {
++ UpgradeCommand(const GlobalEnvironment &env) : Command(env) {}
+ virtual void AddOptions(cmdline::parser &parser) { parser.add<string>("path", 0, ""); }
+ virtual const char *Description() { return "Internal use only!"; }
+ virtual bool IsInternalOnly() { return true; }
+@@ -488,6 +488,7 @@ struct UpgradeCommand : public Command
+ #if defined(RELEASE)
+ struct CrashHandlerCommand : public Command
+ {
++ CrashHandlerCommand(const GlobalEnvironment &env) : Command(env) {}
+ virtual void AddOptions(cmdline::parser &parser) {}
+ virtual const char *Description() { return "Internal use only!"; }
+ virtual bool IsInternalOnly() { return true; }
+@@ -673,6 +674,7 @@ struct CrashHandlerCommand : public Command
+
+ struct GlobalHookCommand : public Command
+ {
++ GlobalHookCommand(const GlobalEnvironment &env) : Command(env) {}
+ virtual void AddOptions(cmdline::parser &parser)
+ {
+ parser.add<string>("match", 0, "");
+@@ -900,18 +902,20 @@ int WINAPI wWinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInstance, _In_
+ return 1;
+ }
+
++ GlobalEnvironment env;
++
+ // perform an upgrade of the UI
+- add_command("upgrade", new UpgradeCommand());
++ add_command("upgrade", new UpgradeCommand(env));
+
+ #if defined(RELEASE)
+ // special WIN32 option for launching the crash handler
+- add_command("crashhandle", new CrashHandlerCommand());
++ add_command("crashhandle", new CrashHandlerCommand(env));
+ #endif
+
+ // this installs a global windows hook pointing at renderdocshim*.dll that filters all running
+ // processes and loads renderdoc.dll in the target one. In any other process it unloads as soon as
+ // possible
+- add_command("globalhook", new GlobalHookCommand());
++ add_command("globalhook", new GlobalHookCommand(env));
+
+- return renderdoccmd(argv);
++ return renderdoccmd(env, argv);
+ }
+--
+2.13.1
+