From ebb889a7eefe1d6659b802c056d0aeecb780de2e Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 22 Jul 2016 18:23:30 +0200 Subject: [PATCH] Report supported windowing systems from replay, and choose which to use * This is primarily for vulkan, which supports either xlib or xcb (and not necessarily both). GL still only supports xlib, windows and android only support one system regardless of API. * This should also support xlib again for fetching keystates etc. --- COMPILE.md | 4 +- qrenderdoc/Windows/TextureViewer.cpp | 57 ++++++++++++-- renderdoc/api/replay/renderdoc_replay.h | 74 ++++++++++++++++-- renderdoc/core/core.cpp | 19 +++++ renderdoc/core/image_viewer.cpp | 9 ++- renderdoc/core/replay_proxy.h | 10 ++- renderdoc/driver/d3d11/d3d11_debug.cpp | 6 +- renderdoc/driver/d3d11/d3d11_debug.h | 2 +- renderdoc/driver/d3d11/d3d11_replay.cpp | 4 +- renderdoc/driver/d3d11/d3d11_replay.h | 9 ++- renderdoc/driver/d3d12/d3d12_debug.cpp | 6 +- renderdoc/driver/d3d12/d3d12_debug.h | 2 +- renderdoc/driver/d3d12/d3d12_replay.cpp | 4 +- renderdoc/driver/d3d12/d3d12_replay.h | 9 ++- renderdoc/driver/gl/gl_debug.cpp | 2 +- renderdoc/driver/gl/gl_replay.h | 14 +++- renderdoc/driver/gl/gl_replay_linux.cpp | 35 ++++++--- renderdoc/driver/gl/gl_replay_win32.cpp | 6 +- renderdoc/driver/vulkan/vk_android.cpp | 4 +- renderdoc/driver/vulkan/vk_core.h | 2 + renderdoc/driver/vulkan/vk_linux.cpp | 86 ++++++++++++++------- renderdoc/driver/vulkan/vk_posix.cpp | 53 +++++++++---- renderdoc/driver/vulkan/vk_replay.cpp | 18 +++-- renderdoc/driver/vulkan/vk_replay.h | 34 +++++--- renderdoc/driver/vulkan/vk_win32.cpp | 6 +- renderdoc/os/posix/linux/linux_stringio.cpp | 76 +++++++++++++++++- renderdoc/replay/replay_driver.h | 4 +- renderdoc/replay/replay_output.cpp | 68 ++++++++++++---- renderdoc/replay/replay_renderer.cpp | 23 ++++-- renderdoc/replay/replay_renderer.h | 13 ++-- renderdoccmd/CMakeLists.txt | 2 +- renderdoccmd/renderdoccmd_android.cpp | 4 +- renderdoccmd/renderdoccmd_linux.cpp | 78 +++++++++++++++++-- renderdoccmd/renderdoccmd_win32.cpp | 3 +- renderdocui/Interop/ReplayRenderer.cs | 16 ++-- 35 files changed, 607 insertions(+), 155 deletions(-) diff --git a/COMPILE.md b/COMPILE.md index f1226ef9d..baf59fb2e 100644 --- a/COMPILE.md +++ b/COMPILE.md @@ -32,13 +32,13 @@ Requirements are linking against -lX11 and -lGL. For qrenderdoc you need qt5 alo This is the apt-get line you'd need to install the requirements on Ubuntu 14.04: ``` -sudo apt-get install libx11-dev mesa-common-dev libgl1-mesa-dev qt5-default libqt5x11extras5-dev libxcb-keysyms1-dev cmake +sudo apt-get install libx11-dev libx11-xcb-dev mesa-common-dev libgl1-mesa-dev qt5-default libqt5x11extras5-dev libxcb-keysyms1-dev cmake ``` For Archlinux (as of 2016.02.01) you'll need: ``` -sudo pacman -S libx11 xcb-util-keysyms mesa mesa-libgl qt5-base qt5-x11extras cmake +sudo pacman -S libx11 libx11-xcb xcb-util-keysyms mesa mesa-libgl qt5-base qt5-x11extras cmake ``` If you know the required packages for another distribution, please share (or pull request this file!) diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index bd9439a03..cb3930959 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -1,3 +1,8 @@ +#if defined(__linux__) +#define RENDERDOC_WINDOWING_XLIB 1 +#define RENDERDOC_WINDOWING_XCB 1 +#endif + #include "TextureViewer.h" #include "Code/Core.h" #include "FlowLayout.h" @@ -5,6 +10,7 @@ #if defined(__linux__) #include +#include #include #include #endif @@ -162,19 +168,54 @@ void TextureViewer::on_render_clicked(QMouseEvent *e) void TextureViewer::OnLogfileLoaded() { #if defined(WIN32) - HWND wnd = (HWND)ui->render->winId(); -#elif defined(__linux__) - xcb_connection_t *display = QX11Info::connection(); - xcb_window_t window = (xcb_window_t)ui->render->winId(); - void *connectionScreenWindow[3] = {(void *)display, (void *)0, (void *)(uintptr_t)window}; - void *wnd = connectionScreenWindow; + WindowingSystem system = eWindowingSystem_Win32; + HWND wnd = (HWND)ui->render->winId(); + +#elif defined(__linux__) + + XCBWindowData xcb = { + QX11Info::connection(), (xcb_window_t)ui->render->winId(), + }; + + XlibWindowData xlib = {QX11Info::display(), (Drawable)ui->render->winId()}; + + rdctype::array systems; + m_Core->Renderer()->BlockInvoke( + [&systems](IReplayRenderer *r) { r->GetSupportedWindowSystems(&systems); }); + + WindowingSystem system = eWindowingSystem_Unknown; + void *wnd = NULL; + + // prefer XCB + for(int32_t i = 0; i < systems.count; i++) + { + if(systems[i] == eWindowingSystem_XCB) + { + system = eWindowingSystem_XCB; + wnd = &xcb; + break; + } + } + + for(int32_t i = 0; wnd == NULL && i < systems.count; i++) + { + if(systems[i] == eWindowingSystem_Xlib) + { + system = eWindowingSystem_Xlib; + wnd = &xlib; + break; + } + } + #else + #error "Unknown platform" + #endif - m_Core->Renderer()->BlockInvoke([wnd, this](IReplayRenderer *r) { - m_Output = r->CreateOutput(wnd, eOutputType_TexDisplay); + m_Core->Renderer()->BlockInvoke([system, wnd, this](IReplayRenderer *r) { + m_Output = r->CreateOutput(system, wnd, eOutputType_TexDisplay); ui->render->SetOutput(m_Output); OutputConfig c = {eOutputType_TexDisplay}; diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index cf312ee4c..325cfdda9 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -55,6 +55,57 @@ typedef uint32_t bool32; #endif +// windowing structures + +#if defined(RENDERDOC_PLATFORM_WIN32) + +// Win32 uses HWND + +#endif + +#if defined(RENDERDOC_WINDOWING_XLIB) + +#include + +#undef None + +struct XlibWindowData +{ + Display *display; + Drawable window; +}; + +#endif + +#if defined(RENDERDOC_WINDOWING_XCB) + +#include + +#undef None + +struct XCBWindowData +{ + xcb_connection_t *connection; + xcb_window_t window; +}; + +#endif + +#if defined(RENDERDOC_PLATFORM_ANDROID) + +// android uses ANativeWindow* + +#endif + +enum WindowingSystem +{ + eWindowingSystem_Unknown, + eWindowingSystem_Win32, + eWindowingSystem_Xlib, + eWindowingSystem_XCB, + eWindowingSystem_Android, +}; + // needs to be declared up here for reference in basic_types extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_FreeArrayMem(const void *mem); @@ -101,11 +152,12 @@ struct IReplayOutput virtual bool SetMeshDisplay(const MeshDisplay &o) = 0; virtual bool ClearThumbnails() = 0; - virtual bool AddThumbnail(void *wnd, ResourceId texID, FormatComponentType typeHint) = 0; + virtual bool AddThumbnail(WindowingSystem system, void *data, ResourceId texID, + FormatComponentType typeHint) = 0; virtual bool Display() = 0; - virtual bool SetPixelContext(void *wnd) = 0; + virtual bool SetPixelContext(WindowingSystem system, void *data) = 0; virtual bool SetPixelContextLocation(uint32_t x, uint32_t y) = 0; virtual void DisablePixelContext() = 0; @@ -136,13 +188,15 @@ extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_SetMeshDisplay(ReplayO extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_ClearThumbnails(ReplayOutput *output); extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_AddThumbnail(ReplayOutput *output, - void *wnd, ResourceId texID, + WindowingSystem system, + void *data, ResourceId texID, FormatComponentType typeHint); extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_Display(ReplayOutput *output); extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_SetPixelContext(ReplayOutput *output, - void *wnd); + WindowingSystem system, + void *data); extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_SetPixelContextLocation(ReplayOutput *output, uint32_t x, uint32_t y); extern "C" RENDERDOC_API void RENDERDOC_CC ReplayOutput_DisablePixelContext(ReplayOutput *output); @@ -164,7 +218,9 @@ struct IReplayRenderer { virtual APIProperties GetAPIProperties() = 0; - virtual ReplayOutput *CreateOutput(void *handle, OutputType type) = 0; + virtual void GetSupportedWindowSystems(rdctype::array *systems) = 0; + + virtual ReplayOutput *CreateOutput(WindowingSystem system, void *data, OutputType type) = 0; virtual void Shutdown() = 0; virtual void ShutdownOutput(ReplayOutput *output) = 0; @@ -251,9 +307,11 @@ struct ReplayRenderer extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_GetAPIProperties(ReplayRenderer *rend, APIProperties *props); -extern "C" RENDERDOC_API ReplayOutput *RENDERDOC_CC ReplayRenderer_CreateOutput(ReplayRenderer *rend, - void *handle, - OutputType type); +extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_GetSupportedWindowSystems( + ReplayRenderer *rend, rdctype::array *systems); + +extern "C" RENDERDOC_API ReplayOutput *RENDERDOC_CC ReplayRenderer_CreateOutput( + ReplayRenderer *rend, WindowingSystem system, void *data, OutputType type); extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_Shutdown(ReplayRenderer *rend); extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_ShutdownOutput(ReplayRenderer *rend, ReplayOutput *output); diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp index b611b8dc7..06c413591 100644 --- a/renderdoc/core/core.cpp +++ b/renderdoc/core/core.cpp @@ -73,6 +73,25 @@ string ToStrHelper::Get(const RDCDriver &el) return tostrBuf; } +template <> +string ToStrHelper::Get(const WindowingSystem &el) +{ + switch(el) + { + case eWindowingSystem_Unknown: return "Unknown"; + case eWindowingSystem_Win32: return "Win32"; + case eWindowingSystem_Xlib: return "Xlib"; + case eWindowingSystem_XCB: return "XCB"; + case eWindowingSystem_Android: return "Android"; + default: break; + } + + char tostrBuf[256] = {0}; + StringFormat::snprintf(tostrBuf, 255, "WindowingSystem<%d>", el); + + return tostrBuf; +} + template <> string ToStrHelper::Get(const RENDERDOC_InputButton &el) { diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index 68104e251..c54a41cf0 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -69,7 +69,14 @@ public: bool IsRemoteProxy() { return true; } void Shutdown() { delete this; } // pass through necessary operations to proxy - uint64_t MakeOutputWindow(void *w, bool depth) { return m_Proxy->MakeOutputWindow(w, depth); } + vector GetSupportedWindowSystems() + { + return m_Proxy->GetSupportedWindowSystems(); + } + uint64_t MakeOutputWindow(WindowingSystem system, void *data, bool depth) + { + return m_Proxy->MakeOutputWindow(system, data, depth); + } void DestroyOutputWindow(uint64_t id) { m_Proxy->DestroyOutputWindow(id); } bool CheckResizeOutputWindow(uint64_t id) { return m_Proxy->CheckResizeOutputWindow(id); } void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) diff --git a/renderdoc/core/replay_proxy.h b/renderdoc/core/replay_proxy.h index b33ab1bd1..4672208dc 100644 --- a/renderdoc/core/replay_proxy.h +++ b/renderdoc/core/replay_proxy.h @@ -114,10 +114,16 @@ public: bool IsRemoteProxy() { return !m_ReplayHost; } void Shutdown() { delete this; } void ReadLogInitialisation() {} - uint64_t MakeOutputWindow(void *w, bool depth) + vector GetSupportedWindowSystems() { if(m_Proxy) - return m_Proxy->MakeOutputWindow(w, depth); + return m_Proxy->GetSupportedWindowSystems(); + return vector(); + } + uint64_t MakeOutputWindow(WindowingSystem system, void *data, bool depth) + { + if(m_Proxy) + return m_Proxy->MakeOutputWindow(system, data, depth); return 0; } void DestroyOutputWindow(uint64_t id) diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index 4a929315a..dd06bc3de 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -1631,10 +1631,12 @@ void D3D11DebugManager::OutputWindow::MakeDSV() } } -uint64_t D3D11DebugManager::MakeOutputWindow(void *w, bool depth) +uint64_t D3D11DebugManager::MakeOutputWindow(WindowingSystem system, void *data, bool depth) { + RDCASSERT(system == eWindowingSystem_Win32, system); + OutputWindow outw; - outw.wnd = (HWND)w; + outw.wnd = (HWND)data; outw.dev = m_WrappedDevice; DXGI_SWAP_CHAIN_DESC swapDesc; diff --git a/renderdoc/driver/d3d11/d3d11_debug.h b/renderdoc/driver/d3d11/d3d11_debug.h index 8d0ed6bdc..36e125b39 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.h +++ b/renderdoc/driver/d3d11/d3d11_debug.h @@ -101,7 +101,7 @@ public: D3D11DebugManager(WrappedID3D11Device *wrapper); ~D3D11DebugManager(); - uint64_t MakeOutputWindow(void *w, bool depth); + uint64_t MakeOutputWindow(WindowingSystem system, void *data, bool depth); void DestroyOutputWindow(uint64_t id); bool CheckResizeOutputWindow(uint64_t id); void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h); diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index d48355ca1..aa7fe55b9 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -1347,9 +1347,9 @@ vector D3D11Replay::GetPassEvents(uint32_t eventID) return passEvents; } -uint64_t D3D11Replay::MakeOutputWindow(void *w, bool depth) +uint64_t D3D11Replay::MakeOutputWindow(WindowingSystem system, void *data, bool depth) { - return m_pDevice->GetDebugManager()->MakeOutputWindow(w, depth); + return m_pDevice->GetDebugManager()->MakeOutputWindow(system, data, depth); } void D3D11Replay::DestroyOutputWindow(uint64_t id) diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index 386b21792..348f92aed 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -75,7 +75,14 @@ public: vector GetPassEvents(uint32_t eventID); - uint64_t MakeOutputWindow(void *w, bool depth); + vector GetSupportedWindowSystems() + { + vector ret; + ret.push_back(eWindowingSystem_Win32); + return ret; + } + + uint64_t MakeOutputWindow(WindowingSystem system, void *data, bool depth); void DestroyOutputWindow(uint64_t id); bool CheckResizeOutputWindow(uint64_t id); void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h); diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp index 94ca01a98..04c402502 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -599,10 +599,12 @@ void D3D12DebugManager::OutputWindow::MakeDSV() } } -uint64_t D3D12DebugManager::MakeOutputWindow(void *w, bool depth) +uint64_t D3D12DebugManager::MakeOutputWindow(WindowingSystem system, void *data, bool depth) { + RDCASSERT(system == eWindowingSystem_Win32, system); + OutputWindow outw; - outw.wnd = (HWND)w; + outw.wnd = (HWND)data; outw.dev = m_WrappedDevice; DXGI_SWAP_CHAIN_DESC swapDesc; diff --git a/renderdoc/driver/d3d12/d3d12_debug.h b/renderdoc/driver/d3d12/d3d12_debug.h index 147eddeba..3aebcf753 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.h +++ b/renderdoc/driver/d3d12/d3d12_debug.h @@ -38,7 +38,7 @@ public: D3D12DebugManager(WrappedID3D12Device *wrapper); ~D3D12DebugManager(); - uint64_t MakeOutputWindow(void *w, bool depth); + uint64_t MakeOutputWindow(WindowingSystem system, void *data, bool depth); void DestroyOutputWindow(uint64_t id); bool CheckResizeOutputWindow(uint64_t id); void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h); diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index 93e91fe31..bb8e62ebf 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -239,9 +239,9 @@ bool D3D12Replay::RenderTexture(TextureDisplay cfg) return m_pDevice->GetDebugManager()->RenderTexture(cfg, true); } -uint64_t D3D12Replay::MakeOutputWindow(void *w, bool depth) +uint64_t D3D12Replay::MakeOutputWindow(WindowingSystem system, void *data, bool depth) { - return m_pDevice->GetDebugManager()->MakeOutputWindow(w, depth); + return m_pDevice->GetDebugManager()->MakeOutputWindow(system, data, depth); } void D3D12Replay::DestroyOutputWindow(uint64_t id) diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index d667ff0d7..a408782c7 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -70,7 +70,14 @@ public: vector GetPassEvents(uint32_t eventID); - uint64_t MakeOutputWindow(void *w, bool depth); + vector GetSupportedWindowSystems() + { + vector ret; + ret.push_back(eWindowingSystem_Win32); + return ret; + } + + uint64_t MakeOutputWindow(WindowingSystem system, void *data, bool depth); void DestroyOutputWindow(uint64_t id); bool CheckResizeOutputWindow(uint64_t id); void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h); diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index bcf534348..99b59b30d 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -219,7 +219,7 @@ void GLReplay::InitDebugData() RenderDoc::Inst().SetProgress(DebugManagerInit, 0.0f); { - uint64_t id = MakeOutputWindow(NULL, true); + uint64_t id = MakeOutputWindow(eWindowingSystem_Unknown, NULL, true); m_DebugID = id; m_DebugCtx = &m_OutputWindows[id]; diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index d882bf845..47cec570a 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -115,7 +115,19 @@ public: vector GetPassEvents(uint32_t eventID); - uint64_t MakeOutputWindow(void *w, bool depth); + vector GetSupportedWindowSystems() + { + vector ret; + // only Xlib supported for GLX. We can't report XCB here since we need + // the Display, and that can't be obtained from XCB. The application is + // free to use XCB internally but it would have to create a hybrid and + // initialise XCB out of Xlib, to be able to provide the display and + // drawable to us. + ret.push_back(eWindowingSystem_Xlib); + return ret; + } + + uint64_t MakeOutputWindow(WindowingSystem system, void *data, bool depth); void DestroyOutputWindow(uint64_t id); bool CheckResizeOutputWindow(uint64_t id); void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h); diff --git a/renderdoc/driver/gl/gl_replay_linux.cpp b/renderdoc/driver/gl/gl_replay_linux.cpp index 557a0584e..52c6fda8a 100644 --- a/renderdoc/driver/gl/gl_replay_linux.cpp +++ b/renderdoc/driver/gl/gl_replay_linux.cpp @@ -23,6 +23,8 @@ * THE SOFTWARE. ******************************************************************************/ +#define RENDERDOC_WINDOWING_XLIB 1 + #include "gl_replay.h" #include #include "gl_driver.h" @@ -63,30 +65,35 @@ void GLReplay::CloseReplayContext() { if(glXDestroyCtxProc) { - glXMakeContextCurrentProc(m_ReplayCtx.dpy, None, None, NULL); + glXMakeContextCurrentProc(m_ReplayCtx.dpy, 0L, 0L, NULL); glXDestroyCtxProc(m_ReplayCtx.dpy, m_ReplayCtx.ctx); } } -uint64_t GLReplay::MakeOutputWindow(void *wn, bool depth) +uint64_t GLReplay::MakeOutputWindow(WindowingSystem system, void *data, bool depth) { - void **displayAndDrawable = (void **)wn; - Display *dpy = NULL; - GLXDrawable wnd = 0; + Drawable draw = 0; - if(wn) + if(system == eWindowingSystem_Xlib) { - dpy = (Display *)displayAndDrawable[0]; - wnd = (GLXDrawable)displayAndDrawable[1]; + XlibWindowData *xlib = (XlibWindowData *)data; + + dpy = xlib->display; + draw = xlib->window; } - else + else if(system == eWindowingSystem_Unknown) { + // allow undefined so that internally we can create a window-less context dpy = XOpenDisplay(NULL); if(dpy == NULL) return 0; } + else + { + RDCERR("Unexpected window system %u", system); + } static int visAttribs[] = {GLX_X_RENDERABLE, True, @@ -140,13 +147,19 @@ uint64_t GLReplay::MakeOutputWindow(void *wn, bool depth) return 0; } - if(wnd == 0) + GLXDrawable wnd = 0; + + if(draw == 0) { // don't care about pbuffer properties as we won't render directly to this int pbAttribs[] = {GLX_PBUFFER_WIDTH, 32, GLX_PBUFFER_HEIGHT, 32, 0}; wnd = glXCreatePbufferProc(dpy, fbcfg[0], pbAttribs); } + else + { + wnd = glXCreateWindow(dpy, fbcfg[0], draw, 0); + } XFree(fbcfg); @@ -183,7 +196,7 @@ void GLReplay::DestroyOutputWindow(uint64_t id) WrappedOpenGL &gl = *m_pDriver; gl.glDeleteFramebuffers(1, &outw.BlitData.readFBO); - glXMakeContextCurrentProc(outw.dpy, None, None, NULL); + glXMakeContextCurrentProc(outw.dpy, 0L, 0L, NULL); glXDestroyCtxProc(outw.dpy, outw.ctx); m_OutputWindows.erase(it); diff --git a/renderdoc/driver/gl/gl_replay_win32.cpp b/renderdoc/driver/gl/gl_replay_win32.cpp index 363800e1a..218126cb8 100644 --- a/renderdoc/driver/gl/gl_replay_win32.cpp +++ b/renderdoc/driver/gl/gl_replay_win32.cpp @@ -68,9 +68,11 @@ void GLReplay::CloseReplayContext() } } -uint64_t GLReplay::MakeOutputWindow(void *wn, bool depth) +uint64_t GLReplay::MakeOutputWindow(WindowingSystem system, void *data, bool depth) { - HWND w = (HWND)wn; + RDCASSERT(system == eWindowingSystem_Win32 || system == eWindowingSystem_Unknown, system); + + HWND w = (HWND)data; if(w == NULL) w = CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdocGLclass", L"", WS_OVERLAPPEDWINDOW, diff --git a/renderdoc/driver/vulkan/vk_android.cpp b/renderdoc/driver/vulkan/vk_android.cpp index d0cbb218a..e9646f70a 100644 --- a/renderdoc/driver/vulkan/vk_android.cpp +++ b/renderdoc/driver/vulkan/vk_android.cpp @@ -25,9 +25,11 @@ #include "vk_core.h" #include "vk_replay.h" -void VulkanReplay::OutputWindow::SetWindowHandle(void *wn) +void VulkanReplay::OutputWindow::SetWindowHandle(WindowingSystem system, void *data) { + RDCASSERT(system == eWindowingSystem_Android, system); wnd = (ANativeWindow *)wn; + m_WindowSystem = system; } void VulkanReplay::OutputWindow::CreateSurface(VkInstance inst) diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 8f5227476..613f35bea 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -246,6 +246,8 @@ private: uint32_t HandlePreCallback(VkCommandBuffer commandBuffer, bool dispatch = false, uint32_t multiDrawOffset = 0); + vector m_SupportedWindowSystems; + uint32_t m_FrameCounter; PerformanceTimer m_FrameTimer; diff --git a/renderdoc/driver/vulkan/vk_linux.cpp b/renderdoc/driver/vulkan/vk_linux.cpp index cc0de8080..2ba526050 100644 --- a/renderdoc/driver/vulkan/vk_linux.cpp +++ b/renderdoc/driver/vulkan/vk_linux.cpp @@ -22,37 +22,60 @@ * THE SOFTWARE. ******************************************************************************/ +#define RENDERDOC_WINDOWING_XLIB 1 +#define RENDERDOC_WINDOWING_XCB 1 + +#include "api/replay/renderdoc_replay.h" + #include "vk_core.h" #include "vk_replay.h" -void VulkanReplay::OutputWindow::SetWindowHandle(void *wn) +void VulkanReplay::OutputWindow::SetWindowHandle(WindowingSystem system, void *data) { - void **connectionScreenWindow = (void **)wn; + m_WindowSystem = system; - connection = (xcb_connection_t *)connectionScreenWindow[0]; - int scr = (int)(uintptr_t)connectionScreenWindow[1]; - wnd = (xcb_window_t)(uintptr_t)connectionScreenWindow[2]; - - const xcb_setup_t *setup = xcb_get_setup(connection); - xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); - while(scr-- > 0) - xcb_screen_next(&iter); - - screen = iter.data; + if(system == eWindowingSystem_Xlib) + { + XlibWindowData *xdata = (XlibWindowData *)data; + xlib.display = xdata->display; + xlib.window = xdata->window; + } + else if(system == eWindowingSystem_XCB) + { + XCBWindowData *xdata = (XCBWindowData *)data; + xcb.connection = xdata->connection; + xcb.window = xdata->window; + } } void VulkanReplay::OutputWindow::CreateSurface(VkInstance inst) { - VkXcbSurfaceCreateInfoKHR createInfo; + if(m_WindowSystem == eWindowingSystem_Xlib) + { + VkXlibSurfaceCreateInfoKHR createInfo; - createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; - createInfo.pNext = NULL; - createInfo.flags = 0; - createInfo.connection = connection; - createInfo.window = wnd; + createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; + createInfo.pNext = NULL; + createInfo.flags = 0; + createInfo.dpy = xlib.display; + createInfo.window = xlib.window; - VkResult vkr = ObjDisp(inst)->CreateXcbSurfaceKHR(Unwrap(inst), &createInfo, NULL, &surface); - RDCASSERTEQUAL(vkr, VK_SUCCESS); + VkResult vkr = ObjDisp(inst)->CreateXlibSurfaceKHR(Unwrap(inst), &createInfo, NULL, &surface); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + } + else if(m_WindowSystem == eWindowingSystem_XCB) + { + VkXcbSurfaceCreateInfoKHR createInfo; + + createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + createInfo.pNext = NULL; + createInfo.flags = 0; + createInfo.connection = xcb.connection; + createInfo.window = xcb.window; + + VkResult vkr = ObjDisp(inst)->CreateXcbSurfaceKHR(Unwrap(inst), &createInfo, NULL, &surface); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + } } void VulkanReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) @@ -62,12 +85,23 @@ void VulkanReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h OutputWindow &outw = m_OutputWindows[id]; - xcb_get_geometry_cookie_t geomCookie = - xcb_get_geometry(outw.connection, outw.wnd); // window is a xcb_drawable_t - xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(outw.connection, geomCookie, NULL); + if(outw.m_WindowSystem == eWindowingSystem_Xlib) + { + XWindowAttributes attr = {}; + XGetWindowAttributes(outw.xlib.display, outw.xlib.window, &attr); - w = (int32_t)geom->width; - h = (int32_t)geom->height; + w = (int32_t)attr.width; + h = (int32_t)attr.height; + } + else if(outw.m_WindowSystem == eWindowingSystem_XCB) + { + xcb_get_geometry_cookie_t geomCookie = + xcb_get_geometry(outw.xcb.connection, outw.xcb.window); // window is a xcb_drawable_t + xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(outw.xcb.connection, geomCookie, NULL); - free(geom); + w = (int32_t)geom->width; + h = (int32_t)geom->height; + + free(geom); + } } diff --git a/renderdoc/driver/vulkan/vk_posix.cpp b/renderdoc/driver/vulkan/vk_posix.cpp index 775585d35..edffb1848 100644 --- a/renderdoc/driver/vulkan/vk_posix.cpp +++ b/renderdoc/driver/vulkan/vk_posix.cpp @@ -57,24 +57,52 @@ bool WrappedVulkan::AddRequiredExtensions(bool instance, vector &extensi bool oneSurfaceTypeSupported = false; #if defined(VK_USE_PLATFORM_XCB_KHR) - // don't add duplicates, and only add if supported - if(supportedExtensions.find(VK_KHR_XCB_SURFACE_EXTENSION_NAME) != supportedExtensions.end() && - std::find(extensionList.begin(), extensionList.end(), VK_KHR_XCB_SURFACE_EXTENSION_NAME) == - extensionList.end()) + // check if supported + if(supportedExtensions.find(VK_KHR_XCB_SURFACE_EXTENSION_NAME) != supportedExtensions.end()) { - extensionList.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); oneSurfaceTypeSupported = true; + + m_SupportedWindowSystems.push_back(eWindowingSystem_XCB); + + // don't add duplicates + if(std::find(extensionList.begin(), extensionList.end(), VK_KHR_XCB_SURFACE_EXTENSION_NAME) == + extensionList.end()) + { + extensionList.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); + } } #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) - // don't add duplicates - if(supportedExtensions.find(VK_KHR_XLIB_SURFACE_EXTENSION_NAME) != supportedExtensions.end() && - std::find(extensionList.begin(), extensionList.end(), VK_KHR_XLIB_SURFACE_EXTENSION_NAME) == - extensionList.end()) + // check if supported + if(supportedExtensions.find(VK_KHR_XLIB_SURFACE_EXTENSION_NAME) != supportedExtensions.end()) { - extensionList.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); oneSurfaceTypeSupported = true; + + m_SupportedWindowSystems.push_back(eWindowingSystem_Xlib); + + // don't add duplicates + if(std::find(extensionList.begin(), extensionList.end(), VK_KHR_XLIB_SURFACE_EXTENSION_NAME) == + extensionList.end()) + { + extensionList.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); + } + } +#endif + +#if defined(VK_USE_PLATFORM_ANDROID_KHR) + // must be supported + RDCASSERT(supportedExtensions.find(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) != + supportedExtensions.end()); + + oneSurfaceTypeSupported = true; + m_SupportedWindowSystems.push_back(eWindowingSystem_Android); + + // don't add duplicates, application will have added this but just be sure + if(std::find(extensionList.begin(), extensionList.end(), + VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == extensionList.end()) + { + extensionList.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); } #endif @@ -111,10 +139,10 @@ VkBool32 WrappedVulkan::vkGetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalD connection, visual_id); } -struct xcb_connection_t; namespace Keyboard { void UseConnection(xcb_connection_t *conn); +void CloneDisplay(Display *dpy); } VkResult WrappedVulkan::vkCreateXcbSurfaceKHR(VkInstance instance, @@ -177,8 +205,7 @@ VkResult WrappedVulkan::vkCreateXlibSurfaceKHR(VkInstance instance, // handle under there somewhere, we just cast. We won't use the resource record for anything wrapped->record = (VkResourceRecord *)pCreateInfo->window; - // VKTODOLOW Should support Xlib here - // Keyboard::UseConnection(pCreateInfo->dpy); + Keyboard::CloneDisplay(pCreateInfo->dpy); } return ret; diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 05bea464b..a6b401678 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -34,13 +34,16 @@ #define VULKAN 1 #include "data/glsl/debuguniforms.h" -VulkanReplay::OutputWindow::OutputWindow() : wnd(NULL_WND_HANDLE), width(0), height(0) +VulkanReplay::OutputWindow::OutputWindow() + : m_WindowSystem(eWindowingSystem_Unknown), width(0), height(0) { surface = VK_NULL_HANDLE; swap = VK_NULL_HANDLE; for(size_t i = 0; i < ARRAY_COUNT(colimg); i++) colimg[i] = VK_NULL_HANDLE; + WINDOW_HANDLE_INIT; + fresh = true; hasDepth = false; @@ -2733,7 +2736,7 @@ bool VulkanReplay::CheckResizeOutputWindow(uint64_t id) OutputWindow &outw = m_OutputWindows[id]; - if(outw.wnd == NULL_WND_HANDLE) + if(outw.m_WindowSystem == eWindowingSystem_Unknown) return false; int32_t w, h; @@ -3082,15 +3085,20 @@ void VulkanReplay::DestroyOutputWindow(uint64_t id) m_OutputWindows.erase(it); } -uint64_t VulkanReplay::MakeOutputWindow(void *wn, bool depth) +vector VulkanReplay::GetSupportedWindowSystems() +{ + return m_pDriver->m_SupportedWindowSystems; +} + +uint64_t VulkanReplay::MakeOutputWindow(WindowingSystem system, void *data, bool depth) { uint64_t id = m_OutputWinID; m_OutputWinID++; - m_OutputWindows[id].SetWindowHandle(wn); + m_OutputWindows[id].SetWindowHandle(system, data); m_OutputWindows[id].m_ResourceManager = GetResourceManager(); - if(wn != NULL) + if(system != eWindowingSystem_Unknown) { int32_t w, h; GetOutputWindowDimensions(id, w, h); diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index f8f71ea90..6a26df646 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -34,21 +34,29 @@ #include #define WINDOW_HANDLE_DECL HWND wnd; -#define NULL_WND_HANDLE NULL +#define WINDOW_HANDLE_INIT wnd = NULL; #elif defined(RENDERDOC_PLATFORM_ANDROID) #define WINDOW_HANDLE_DECL ANativeWindow *wnd; -#define NULL_WND_HANDLE NULL +#define WINDOW_HANDLE_INIT wnd = NULL; #elif defined(RENDERDOC_PLATFORM_LINUX) -#include -#define WINDOW_HANDLE_DECL \ - xcb_connection_t *connection; \ - xcb_screen_t *screen; \ - xcb_window_t wnd; -#define NULL_WND_HANDLE xcb_window_t(0) +#define WINDOW_HANDLE_DECL \ + struct \ + { \ + Display *display; \ + Drawable window; \ + } xlib; \ + struct \ + { \ + xcb_connection_t *connection; \ + xcb_window_t window; \ + } xcb; +#define WINDOW_HANDLE_INIT \ + RDCEraseEl(xlib); \ + RDCEraseEl(xcb); #else @@ -119,7 +127,9 @@ public: vector GetPassEvents(uint32_t eventID); - uint64_t MakeOutputWindow(void *w, bool depth); + vector GetSupportedWindowSystems(); + + uint64_t MakeOutputWindow(WindowingSystem system, void *data, bool depth); void DestroyOutputWindow(uint64_t id); bool CheckResizeOutputWindow(uint64_t id); void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h); @@ -223,9 +233,11 @@ private: // implemented in vk_replay_platform.cpp void CreateSurface(VkInstance inst); - void SetWindowHandle(void *wn); + void SetWindowHandle(WindowingSystem system, void *data); - WINDOW_HANDLE_DECL + WindowingSystem m_WindowSystem; + + WINDOW_HANDLE_DECL; bool fresh; diff --git a/renderdoc/driver/vulkan/vk_win32.cpp b/renderdoc/driver/vulkan/vk_win32.cpp index d9c439283..816c12c11 100644 --- a/renderdoc/driver/vulkan/vk_win32.cpp +++ b/renderdoc/driver/vulkan/vk_win32.cpp @@ -27,9 +27,11 @@ static int dllLocator = 0; -void VulkanReplay::OutputWindow::SetWindowHandle(void *wn) +void VulkanReplay::OutputWindow::SetWindowHandle(WindowingSystem system, void *data) { - wnd = (HWND)wn; + RDCASSERT(system == eWindowingSystem_Win32, system); + wnd = (HWND)data; + m_WindowSystem = system; } void VulkanReplay::OutputWindow::CreateSurface(VkInstance inst) diff --git a/renderdoc/os/posix/linux/linux_stringio.cpp b/renderdoc/os/posix/linux/linux_stringio.cpp index acff0e5f8..f344c3590 100644 --- a/renderdoc/os/posix/linux/linux_stringio.cpp +++ b/renderdoc/os/posix/linux/linux_stringio.cpp @@ -52,13 +52,19 @@ bool PlatformHasKeyInput() return true; } -xcb_connection_t *connection; -xcb_key_symbols_t *symbols; +Display *CurrentXDisplay = NULL; void CloneDisplay(Display *dpy) { + if(CurrentXDisplay || dpy == NULL) + return; + + CurrentXDisplay = XOpenDisplay(XDisplayString(dpy)); } +xcb_connection_t *connection; +xcb_key_symbols_t *symbols; + void UseConnection(xcb_connection_t *conn) { connection = conn; @@ -74,13 +80,72 @@ void RemoveInputWindow(void *wnd) { } -bool GetKeyState(int key) +bool GetXlibKeyState(int key) { + if(CurrentXDisplay == NULL) + return false; + KeySym ks = 0; + if(key >= eRENDERDOC_Key_A && key <= eRENDERDOC_Key_Z) + ks = key; + if(key >= eRENDERDOC_Key_0 && key <= eRENDERDOC_Key_9) + ks = key; + + switch(key) + { + case eRENDERDOC_Key_Divide: ks = XK_KP_Divide; break; + case eRENDERDOC_Key_Multiply: ks = XK_KP_Multiply; break; + case eRENDERDOC_Key_Subtract: ks = XK_KP_Subtract; break; + case eRENDERDOC_Key_Plus: ks = XK_KP_Add; break; + case eRENDERDOC_Key_F1: ks = XK_F1; break; + case eRENDERDOC_Key_F2: ks = XK_F2; break; + case eRENDERDOC_Key_F3: ks = XK_F3; break; + case eRENDERDOC_Key_F4: ks = XK_F4; break; + case eRENDERDOC_Key_F5: ks = XK_F5; break; + case eRENDERDOC_Key_F6: ks = XK_F6; break; + case eRENDERDOC_Key_F7: ks = XK_F7; break; + case eRENDERDOC_Key_F8: ks = XK_F8; break; + case eRENDERDOC_Key_F9: ks = XK_F9; break; + case eRENDERDOC_Key_F10: ks = XK_F10; break; + case eRENDERDOC_Key_F11: ks = XK_F11; break; + case eRENDERDOC_Key_F12: ks = XK_F12; break; + case eRENDERDOC_Key_Home: ks = XK_Home; break; + case eRENDERDOC_Key_End: ks = XK_End; break; + case eRENDERDOC_Key_Insert: ks = XK_Insert; break; + case eRENDERDOC_Key_Delete: ks = XK_Delete; break; + case eRENDERDOC_Key_PageUp: ks = XK_Prior; break; + case eRENDERDOC_Key_PageDn: ks = XK_Next; break; + case eRENDERDOC_Key_Backspace: ks = XK_BackSpace; break; + case eRENDERDOC_Key_Tab: ks = XK_Tab; break; + case eRENDERDOC_Key_PrtScrn: ks = XK_Print; break; + case eRENDERDOC_Key_Pause: ks = XK_Pause; break; + default: break; + } + + if(ks == 0) + return false; + + KeyCode kc = XKeysymToKeycode(CurrentXDisplay, ks); + + char keyState[32]; + XQueryKeymap(CurrentXDisplay, keyState); + + int byteIdx = (kc / 8); + int bitMask = 1 << (kc % 8); + + uint8_t keyByte = (uint8_t)keyState[byteIdx]; + + return (keyByte & bitMask) != 0; +} + +bool GetXCBKeyState(int key) +{ if(symbols == NULL) return false; + KeySym ks = 0; + if(key >= eRENDERDOC_Key_A && key <= eRENDERDOC_Key_Z) ks = key; if(key >= eRENDERDOC_Key_0 && key <= eRENDERDOC_Key_9) @@ -143,6 +208,11 @@ bool GetKeyState(int key) return ret; } + +bool GetKeyState(int key) +{ + return GetXCBKeyState(key) || GetXlibKeyState(key); +} } namespace FileIO diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index ea56edd02..75818b4ca 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -134,7 +134,9 @@ class IReplayDriver : public IRemoteDriver public: virtual bool IsRemoteProxy() = 0; - virtual uint64_t MakeOutputWindow(void *w, bool depth) = 0; + virtual vector GetSupportedWindowSystems() = 0; + + virtual uint64_t MakeOutputWindow(WindowingSystem system, void *data, bool depth) = 0; virtual void DestroyOutputWindow(uint64_t id) = 0; virtual bool CheckResizeOutputWindow(uint64_t id) = 0; virtual void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h) = 0; diff --git a/renderdoc/replay/replay_output.cpp b/renderdoc/replay/replay_output.cpp index b6afc32bb..3dccd2818 100644 --- a/renderdoc/replay/replay_output.cpp +++ b/renderdoc/replay/replay_output.cpp @@ -23,12 +23,46 @@ * THE SOFTWARE. ******************************************************************************/ +#if defined(RENDERDOC_PLATFORM_LINUX) +#define RENDERDOC_WINDOWING_XLIB 1 +#define RENDERDOC_WINDOWING_XCB 1 +#endif + #include "common/common.h" #include "maths/matrix.h" #include "serialise/string_utils.h" #include "replay_renderer.h" -ReplayOutput::ReplayOutput(ReplayRenderer *parent, void *w, OutputType type) +static uint64_t GetHandle(WindowingSystem system, void *data) +{ +#if defined(RENDERDOC_PLATFORM_LINUX) + + if(system == eWindowingSystem_Xlib) + return (uint64_t)((XlibWindowData *)data)->window; + + if(system == eWindowingSystem_XCB) + return (uint64_t)((XCBWindowData *)data)->window; + + RDCERR("Unrecognised window system %d", system); + + return 0; + +#elif defined(RENDERDOC_PLATFORM_WIN32) + + RDCASSERT(system == eWindowingSystem_Win32); + return (uint64_t)data; // HWND + +#elif defined(RENDERDOC_PLATFORM_ANDROID) + + RDCASSERT(system == eWindowingSystem_Android); + return (uint64_t)data; // ANativeWindow * + +#else + RDCFATAL("No windowing data defined for this platform! Must be implemented for replay outputs"); +#endif +} + +ReplayOutput::ReplayOutput(ReplayRenderer *parent, WindowingSystem system, void *data, OutputType type) { m_pRenderer = parent; @@ -45,7 +79,6 @@ ReplayOutput::ReplayOutput(ReplayRenderer *parent, void *w, OutputType type) RDCEraseEl(m_RenderData); - m_PixelContext.wndHandle = 0; m_PixelContext.outputID = 0; m_PixelContext.texture = ResourceId(); m_PixelContext.depthMode = false; @@ -55,8 +88,9 @@ ReplayOutput::ReplayOutput(ReplayRenderer *parent, void *w, OutputType type) m_Config.m_Type = type; - if(w) - m_MainOutput.outputID = m_pDevice->MakeOutputWindow(w, type == eOutputType_MeshDisplay); + if(system != eWindowingSystem_Unknown) + m_MainOutput.outputID = + m_pDevice->MakeOutputWindow(system, data, type == eOutputType_MeshDisplay); else m_MainOutput.outputID = 0; m_MainOutput.texture = ResourceId(); @@ -179,10 +213,9 @@ bool ReplayOutput::ClearThumbnails() return true; } -bool ReplayOutput::SetPixelContext(void *wnd) +bool ReplayOutput::SetPixelContext(WindowingSystem system, void *data) { - m_PixelContext.wndHandle = wnd; - m_PixelContext.outputID = m_pDevice->MakeOutputWindow(m_PixelContext.wndHandle, false); + m_PixelContext.outputID = m_pDevice->MakeOutputWindow(system, data, false); m_PixelContext.texture = ResourceId(); m_PixelContext.depthMode = false; @@ -191,11 +224,12 @@ bool ReplayOutput::SetPixelContext(void *wnd) return true; } -bool ReplayOutput::AddThumbnail(void *wnd, ResourceId texID, FormatComponentType typeHint) +bool ReplayOutput::AddThumbnail(WindowingSystem system, void *data, ResourceId texID, + FormatComponentType typeHint) { OutputPair p; - RDCASSERT(wnd); + RDCASSERT(data); bool depthMode = false; @@ -211,7 +245,7 @@ bool ReplayOutput::AddThumbnail(void *wnd, ResourceId texID, FormatComponentType for(size_t i = 0; i < m_Thumbnails.size(); i++) { - if(m_Thumbnails[i].wndHandle == wnd) + if(m_Thumbnails[i].wndHandle == GetHandle(system, data)) { m_Thumbnails[i].texture = texID; @@ -225,8 +259,8 @@ bool ReplayOutput::AddThumbnail(void *wnd, ResourceId texID, FormatComponentType } } - p.wndHandle = wnd; - p.outputID = m_pDevice->MakeOutputWindow(p.wndHandle, false); + p.wndHandle = GetHandle(system, data); + p.outputID = m_pDevice->MakeOutputWindow(system, data, false); p.texture = texID; p.depthMode = depthMode; p.typeHint = typeHint; @@ -700,10 +734,11 @@ extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_ClearThumbnails(Replay return output->ClearThumbnails(); } extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_AddThumbnail(ReplayOutput *output, - void *wnd, ResourceId texID, + WindowingSystem system, + void *data, ResourceId texID, FormatComponentType typeHint) { - return output->AddThumbnail(wnd, texID, typeHint); + return output->AddThumbnail(system, data, texID, typeHint); } extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_Display(ReplayOutput *output) @@ -712,9 +747,10 @@ extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_Display(ReplayOutput * } extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_SetPixelContext(ReplayOutput *output, - void *wnd) + WindowingSystem system, + void *data) { - return output->SetPixelContext(wnd); + return output->SetPixelContext(system, data); } extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_SetPixelContextLocation(ReplayOutput *output, uint32_t x, uint32_t y) diff --git a/renderdoc/replay/replay_renderer.cpp b/renderdoc/replay/replay_renderer.cpp index 1a8a093d4..41189e5c1 100644 --- a/renderdoc/replay/replay_renderer.cpp +++ b/renderdoc/replay/replay_renderer.cpp @@ -1415,9 +1415,15 @@ bool ReplayRenderer::GetCBufferVariableContents(ResourceId shader, const char *e return true; } -ReplayOutput *ReplayRenderer::CreateOutput(void *wndhandle, OutputType type) +void ReplayRenderer::GetSupportedWindowSystems(rdctype::array *systems) { - ReplayOutput *out = new ReplayOutput(this, wndhandle, type); + if(systems) + *systems = m_pDevice->GetSupportedWindowSystems(); +} + +ReplayOutput *ReplayRenderer::CreateOutput(WindowingSystem system, void *data, OutputType type) +{ + ReplayOutput *out = new ReplayOutput(this, system, data, type); m_Outputs.push_back(out); @@ -1668,11 +1674,16 @@ extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_GetAPIProperties(Repla *props = rend->GetAPIProperties(); } -extern "C" RENDERDOC_API ReplayOutput *RENDERDOC_CC ReplayRenderer_CreateOutput(ReplayRenderer *rend, - void *handle, - OutputType type) +extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_GetSupportedWindowSystems( + ReplayRenderer *rend, rdctype::array *systems) { - return rend->CreateOutput(handle, type); + rend->GetSupportedWindowSystems(systems); +} + +extern "C" RENDERDOC_API ReplayOutput *RENDERDOC_CC ReplayRenderer_CreateOutput( + ReplayRenderer *rend, WindowingSystem system, void *data, OutputType type) +{ + return rend->CreateOutput(system, data, type); } extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_Shutdown(ReplayRenderer *rend) { diff --git a/renderdoc/replay/replay_renderer.h b/renderdoc/replay/replay_renderer.h index 59aa80eb2..cb2a69c40 100644 --- a/renderdoc/replay/replay_renderer.h +++ b/renderdoc/replay/replay_renderer.h @@ -43,12 +43,13 @@ public: bool SetMeshDisplay(const MeshDisplay &o); bool ClearThumbnails(); - bool AddThumbnail(void *wnd, ResourceId texID, FormatComponentType typeHint); + bool AddThumbnail(WindowingSystem system, void *data, ResourceId texID, + FormatComponentType typeHint); bool Display(); OutputType GetType() { return m_Config.m_Type; } - bool SetPixelContext(void *wnd); + bool SetPixelContext(WindowingSystem system, void *data); bool SetPixelContextLocation(uint32_t x, uint32_t y); void DisablePixelContext(); @@ -58,7 +59,7 @@ public: uint32_t PickVertex(uint32_t eventID, uint32_t x, uint32_t y); private: - ReplayOutput(ReplayRenderer *parent, void *w, OutputType type); + ReplayOutput(ReplayRenderer *parent, WindowingSystem system, void *data, OutputType type); virtual ~ReplayOutput(); void SetFrameEvent(int eventID); @@ -82,7 +83,7 @@ private: { ResourceId texture; bool depthMode; - void *wndHandle; + uint64_t wndHandle; FormatComponentType typeHint; uint64_t outputID; @@ -191,7 +192,9 @@ public: ResourceId buffer, uint64_t offs, rdctype::array *vars); - ReplayOutput *CreateOutput(void *handle, OutputType type); + void GetSupportedWindowSystems(rdctype::array *systems); + + ReplayOutput *CreateOutput(WindowingSystem, void *data, OutputType type); void ShutdownOutput(ReplayOutput *output); void Shutdown(); diff --git a/renderdoccmd/CMakeLists.txt b/renderdoccmd/CMakeLists.txt index c016ff6ed..f53fd3b8c 100644 --- a/renderdoccmd/CMakeLists.txt +++ b/renderdoccmd/CMakeLists.txt @@ -15,7 +15,7 @@ elseif(UNIX) list(APPEND includes PRIVATE ${OPENGL_INCLUDE_DIR}) list(APPEND libraries PRIVATE ${OPENGL_gl_LIBRARY}) - list(APPEND libraries PRIVATE -lxcb) + list(APPEND libraries PRIVATE -lxcb -lX11 -lX11-xcb) endif() if(ANDROID) diff --git a/renderdoccmd/renderdoccmd_android.cpp b/renderdoccmd/renderdoccmd_android.cpp index 1d7ccfa86..c642c5ac2 100644 --- a/renderdoccmd/renderdoccmd_android.cpp +++ b/renderdoccmd/renderdoccmd_android.cpp @@ -47,8 +47,8 @@ void DisplayRendererPreview(ReplayRenderer *renderer, TextureDisplay &displayCfg { ANativeWindow *connectionScreenWindow = android_state->window; - ReplayOutput *out = - ReplayRenderer_CreateOutput(renderer, connectionScreenWindow, eOutputType_TexDisplay); + ReplayOutput *out = ReplayRenderer_CreateOutput(renderer, eWindowingSystem_Android, + connectionScreenWindow, eOutputType_TexDisplay); OutputConfig c = {eOutputType_TexDisplay}; diff --git a/renderdoccmd/renderdoccmd_linux.cpp b/renderdoccmd/renderdoccmd_linux.cpp index 9c92066a2..27fb5880c 100644 --- a/renderdoccmd/renderdoccmd_linux.cpp +++ b/renderdoccmd/renderdoccmd_linux.cpp @@ -24,23 +24,47 @@ ******************************************************************************/ #include "renderdoccmd.h" +#include #include #include -#include #include #include #include -#include #include +#define RENDERDOC_WINDOWING_XLIB 1 +#define RENDERDOC_WINDOWING_XCB 1 +#include + using std::string; void DisplayRendererPreview(ReplayRenderer *renderer, TextureDisplay &displayCfg, uint32_t width, uint32_t height) { - int scr; + // need to create a hybrid setup xlib and xcb in case only one or the other is supported. + // We'll prefer xcb + + Display *display = XOpenDisplay(NULL); + + if(display == NULL) + { + std::cerr << "Couldn't open X Display" << std::endl; + return; + } + + int scr = DefaultScreen(display); + + xcb_connection_t *connection = XGetXCBConnection(display); + + if(connection == NULL) + { + XCloseDisplay(display); + std::cerr << "Couldn't get XCB connection from Xlib Display" << std::endl; + return; + } + + XSetEventQueueOwner(display, XCBOwnsEventQueue); - xcb_connection_t *connection = xcb_connect(NULL, &scr); const xcb_setup_t *setup = xcb_get_setup(connection); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); while(scr-- > 0) @@ -76,11 +100,49 @@ void DisplayRendererPreview(ReplayRenderer *renderer, TextureDisplay &displayCfg xcb_map_window(connection, window); - void *connectionScreenWindow[] = {(void *)connection, (void *)(uintptr_t)scr, - (void *)(uintptr_t)window}; + rdctype::array systems; + ReplayRenderer_GetSupportedWindowSystems(renderer, &systems); - ReplayOutput *out = - ReplayRenderer_CreateOutput(renderer, connectionScreenWindow, eOutputType_TexDisplay); + bool xcb = false, xlib = false; + + for(int32_t i = 0; i < systems.count; i++) + { + if(systems[i] == eWindowingSystem_Xlib) + xlib = true; + if(systems[i] == eWindowingSystem_XCB) + xcb = true; + } + + ReplayOutput *out = NULL; + + // prefer xcb + if(xcb) + { + XCBWindowData windowData; + windowData.connection = connection; + windowData.window = window; + + out = ReplayRenderer_CreateOutput(renderer, eWindowingSystem_XCB, &windowData, + eOutputType_TexDisplay); + } + else if(xlib) + { + XlibWindowData windowData; + windowData.display = display; + windowData.window = (Drawable)window; // safe to cast types + + out = ReplayRenderer_CreateOutput(renderer, eWindowingSystem_Xlib, &windowData, + eOutputType_TexDisplay); + } + else + { + std::cerr << "Neither XCB nor XLib are supported, can't create window." << std::endl; + std::cerr << "Supported systems: "; + for(int32_t i = 0; i < systems.count; i++) + std::cerr << systems[i] << std::endl; + std::cerr << std::endl; + return; + } OutputConfig c = {eOutputType_TexDisplay}; diff --git a/renderdoccmd/renderdoccmd_win32.cpp b/renderdoccmd/renderdoccmd_win32.cpp index 3cdcac239..2c4905888 100644 --- a/renderdoccmd/renderdoccmd_win32.cpp +++ b/renderdoccmd/renderdoccmd_win32.cpp @@ -232,7 +232,8 @@ void DisplayRendererPreview(ReplayRenderer *renderer, TextureDisplay &displayCfg ShowWindow(wnd, SW_SHOW); UpdateWindow(wnd); - ReplayOutput *out = ReplayRenderer_CreateOutput(renderer, wnd, eOutputType_TexDisplay); + ReplayOutput *out = + ReplayRenderer_CreateOutput(renderer, eWindowingSystem_Win32, wnd, eOutputType_TexDisplay); OutputConfig c = {eOutputType_TexDisplay}; diff --git a/renderdocui/Interop/ReplayRenderer.cs b/renderdocui/Interop/ReplayRenderer.cs index 6dd28011c..26e2fce72 100644 --- a/renderdocui/Interop/ReplayRenderer.cs +++ b/renderdocui/Interop/ReplayRenderer.cs @@ -88,13 +88,13 @@ namespace renderdoc [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayOutput_ClearThumbnails(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] - private static extern bool ReplayOutput_AddThumbnail(IntPtr real, IntPtr wnd, ResourceId texID, FormatComponentType typeHint); + private static extern bool ReplayOutput_AddThumbnail(IntPtr real, UInt32 windowSystem, IntPtr wnd, ResourceId texID, FormatComponentType typeHint); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayOutput_Display(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] - private static extern bool ReplayOutput_SetPixelContext(IntPtr real, IntPtr wnd); + private static extern bool ReplayOutput_SetPixelContext(IntPtr real, UInt32 windowSystem, IntPtr wnd); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayOutput_SetPixelContextLocation(IntPtr real, UInt32 x, UInt32 y); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] @@ -132,7 +132,8 @@ namespace renderdoc } public bool AddThumbnail(IntPtr wnd, ResourceId texID, FormatComponentType typeHint) { - return ReplayOutput_AddThumbnail(m_Real, wnd, texID, typeHint); + // 1 == eWindowingSystem_Win32 + return ReplayOutput_AddThumbnail(m_Real, 1u, wnd, texID, typeHint); } public bool Display() @@ -142,7 +143,8 @@ namespace renderdoc public bool SetPixelContext(IntPtr wnd) { - return ReplayOutput_SetPixelContext(m_Real, wnd); + // 1 == eWindowingSystem_Win32 + return ReplayOutput_SetPixelContext(m_Real, 1u, wnd); } public bool SetPixelContextLocation(UInt32 x, UInt32 y) { @@ -194,7 +196,7 @@ namespace renderdoc private static extern void ReplayRenderer_GetAPIProperties(IntPtr real, IntPtr propsOut); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr ReplayRenderer_CreateOutput(IntPtr real, IntPtr WindowHandle, OutputType type); + private static extern IntPtr ReplayRenderer_CreateOutput(IntPtr real, UInt32 windowSystem, IntPtr WindowHandle, OutputType type); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void ReplayRenderer_ShutdownOutput(IntPtr real, IntPtr replayOutput); @@ -309,7 +311,9 @@ namespace renderdoc public ReplayOutput CreateOutput(IntPtr WindowHandle, OutputType type) { - IntPtr ret = ReplayRenderer_CreateOutput(m_Real, WindowHandle, type); + // 0 == eWindowingSystem_Unknown + // 1 == eWindowingSystem_Win32 + IntPtr ret = ReplayRenderer_CreateOutput(m_Real, WindowHandle == IntPtr.Zero ? 0u : 1u, WindowHandle, type); if (ret == IntPtr.Zero) return null;