Add experimental wayland support. Refs #853

* This is only lightly tested and may break heavily. It is disabled by default
 and must be explicitly enabled.
* In particular this is only known to work for Wayland use at capture time.
 Wayland on replay is still unsupported. Known issues include: EGL pbuffer
 surfaces are not implemented on Wayland, Wayland cannot get window dimensions,
 and there are hangs/failures with GL and vulkan presentation with Wayland.
This commit is contained in:
baldurk
2019-08-29 20:48:39 +01:00
parent 9b501d88a1
commit 6d40bbb783
48 changed files with 1051 additions and 185 deletions
+24
View File
@@ -166,6 +166,7 @@ option(ENABLE_PYRENDERDOC "Enable renderdoc python modules" ON)
option(ENABLE_XLIB "Enable xlib windowing support" ON) option(ENABLE_XLIB "Enable xlib windowing support" ON)
option(ENABLE_XCB "Enable xcb windowing support" ON) option(ENABLE_XCB "Enable xcb windowing support" ON)
option(ENABLE_WAYLAND "Enable experimental wayland windowing support" OFF)
option(ENABLE_GGP "Enable GGP support" OFF) option(ENABLE_GGP "Enable GGP support" OFF)
option(ENABLE_ASAN "Enable address sanitizer" OFF) option(ENABLE_ASAN "Enable address sanitizer" OFF)
@@ -182,6 +183,21 @@ if(ENABLE_TSAN)
message(STATUS "Enabling thread sanitizer - may cause issues if capturing, only recommended for use with replay only") message(STATUS "Enabling thread sanitizer - may cause issues if capturing, only recommended for use with replay only")
endif() endif()
if(ENABLE_WAYLAND)
find_package(PkgConfig REQUIRED)
pkg_check_modules(PKG_WAYLAND QUIET wayland-client)
if(PKG_WAYLAND_FOUND)
if(NOT ENABLE_GLES)
message(WARNING "On Wayland GLES support is required for EGL, disabling GL support")
set(ENABLE_GL OFF CACHE BOOL "" FORCE)
endif()
else()
message(WARNING "Wayland not found - disabling support")
set(ENABLE_WAYLAND OFF CACHE BOOL "" FORCE)
endif()
endif()
if(WIN32) if(WIN32)
message(FATAL_ERROR "CMake is not needed on Windows, just open and build renderdoc.sln") message(FATAL_ERROR "CMake is not needed on Windows, just open and build renderdoc.sln")
endif() endif()
@@ -328,6 +344,10 @@ elseif(UNIX)
if(ENABLE_XCB) if(ENABLE_XCB)
add_definitions(-DRENDERDOC_WINDOWING_XCB) add_definitions(-DRENDERDOC_WINDOWING_XCB)
endif() endif()
if(ENABLE_WAYLAND)
add_definitions(-DRENDERDOC_WINDOWING_WAYLAND)
endif()
endif() endif()
add_subdirectory(renderdoc) add_subdirectory(renderdoc)
@@ -379,5 +399,9 @@ if(UNIX AND NOT ANDROID AND NOT APPLE AND NOT ENABLE_GGP)
if(ENABLE_XCB) if(ENABLE_XCB)
message(STATUS " - XCB") message(STATUS " - XCB")
endif() endif()
if(ENABLE_WAYLAND)
message(STATUS " - Wayland")
endif()
endif() endif()
+3 -2
View File
@@ -373,10 +373,11 @@ The path follows the template set in :cpp:func:`SetCaptureFilePathTemplate` so i
* For D3D11 it must be the ``ID3D11Device`` device object. * For D3D11 it must be the ``ID3D11Device`` device object.
* For D3D12 it must be the ``ID3D12Device`` device object. * For D3D12 it must be the ``ID3D12Device`` device object.
* For OpenGL it must be the ``HGLRC`` or ``GLXContext`` context object. * For OpenGL it must be the ``HGLRC``, ``GLXContext``, or ``EGLContext`` context object.
* For OpenGLES it must be the ``EGLContext`` context object.
* For Vulkan it must be the dispatch table pointer within the ``VkInstance``. This is a pointer-sized value at the location pointed to by the ``VkInstance``. NOTE - this is not the actual ``VkInstance`` pointer itself. You can use the RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE helper macro defined in the renderdoc header to obtain this pointer from any VkInstance. * For Vulkan it must be the dispatch table pointer within the ``VkInstance``. This is a pointer-sized value at the location pointed to by the ``VkInstance``. NOTE - this is not the actual ``VkInstance`` pointer itself. You can use the RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE helper macro defined in the renderdoc header to obtain this pointer from any VkInstance.
``RENDERDOC_WindowHandle`` is a typedef to ``void *``. It is the platform specific ``HWND``, ``xcb_window_t``, or Xlib ``Window``. ``RENDERDOC_WindowHandle`` is a typedef to ``void *``. It is the platform specific Windows ``HWND``, Xcb ``xcb_window_t``, Xlib ``Window`` / ``Drawable``, Wayland ``wl_surface*``, or Android ``ANativeWindow*``.
.. cpp:function:: void StartFrameCapture(RENDERDOC_DevicePointer device, RENDERDOC_WindowHandle wndHandle) .. cpp:function:: void StartFrameCapture(RENDERDOC_DevicePointer device, RENDERDOC_WindowHandle wndHandle)
+7
View File
@@ -168,6 +168,13 @@ if(CMAKE_COMPILER_IS_GNUCXX)
"QMAKE_CXXFLAGS+=-Wno-unknown-warning -Wno-implicit-fallthrough -Wno-cast-function-type -Wno-stringop-truncation\n") "QMAKE_CXXFLAGS+=-Wno-unknown-warning -Wno-implicit-fallthrough -Wno-cast-function-type -Wno-stringop-truncation\n")
endif() endif()
if(ENABLE_WAYLAND)
message(WARNING "!!!! Using the Wayland Qt platform in qrenderdoc is NOT SUPPORTED !!!!")
file(APPEND
${CMAKE_BINARY_DIR}/qrenderdoc/qrenderdoc_cmake.pri
"DEFINES+=RENDERDOC_WINDOWING_WAYLAND\n")
endif()
# propagate build version info. Lots of escaping needed here to pass ""s into the define value # propagate build version info. Lots of escaping needed here to pass ""s into the define value
if(BUILD_VERSION_STABLE) if(BUILD_VERSION_STABLE)
file(APPEND file(APPEND
+54 -12
View File
@@ -849,22 +849,48 @@ void CaptureContext::LoadCaptureThreaded(const QString &captureFile, const Repla
#if defined(RENDERDOC_PLATFORM_WIN32) #if defined(RENDERDOC_PLATFORM_WIN32)
m_CurWinSystem = WindowingSystem::Win32; m_CurWinSystem = WindowingSystem::Win32;
#elif defined(RENDERDOC_PLATFORM_LINUX) #elif defined(RENDERDOC_PLATFORM_LINUX)
m_CurWinSystem = WindowingSystem::Xlib; m_CurWinSystem = WindowingSystem::Unknown;
// prefer XCB, if supported if(QGuiApplication::platformName() == lit("wayland"))
for(WindowingSystem sys : m_WinSystems)
{ {
if(sys == WindowingSystem::XCB) // if we're using Wayland we must use wayland since we can't get any other surface type
for(WindowingSystem sys : m_WinSystems)
{ {
m_CurWinSystem = WindowingSystem::XCB; if(sys == WindowingSystem::Wayland)
break; {
m_CurWinSystem = WindowingSystem::Wayland;
m_WaylandDisplay = (wl_display *)AccessWaylandPlatformInterface("display", NULL);
break;
}
}
if(m_CurWinSystem == WindowingSystem::Unknown)
{
RDDialog::critical(NULL, tr("No wayland support"),
tr("Replay doesn't support Wayland surfaces - check you compiled this "
"build of RenderDoc with Wayland support enabled."));
} }
} }
if(m_CurWinSystem == WindowingSystem::XCB)
m_XCBConnection = QX11Info::connection();
else else
m_X11Display = QX11Info::display(); {
m_CurWinSystem = WindowingSystem::Xlib;
// prefer XCB, if supported
for(WindowingSystem sys : m_WinSystems)
{
if(sys == WindowingSystem::XCB)
{
m_CurWinSystem = WindowingSystem::XCB;
break;
}
}
if(m_CurWinSystem == WindowingSystem::XCB)
m_XCBConnection = QX11Info::connection();
else
m_X11Display = QX11Info::display();
}
#elif defined(RENDERDOC_PLATFORM_APPLE) #elif defined(RENDERDOC_PLATFORM_APPLE)
m_CurWinSystem = WindowingSystem::MacOS; m_CurWinSystem = WindowingSystem::MacOS;
#endif #endif
@@ -1777,10 +1803,26 @@ WindowingData CaptureContext::CreateWindowingData(QWidget *window)
#elif defined(RENDERDOC_PLATFORM_LINUX) #elif defined(RENDERDOC_PLATFORM_LINUX)
if(m_CurWinSystem == WindowingSystem::XCB) if(m_CurWinSystem == WindowingSystem::Wayland)
{
// we don't need this, we just need to force creation of a window handle
window->winId();
wl_surface *surface =
(wl_surface *)AccessWaylandPlatformInterface("surface", window->windowHandle());
return CreateWaylandWindowingData(m_WaylandDisplay, surface);
}
else if(m_CurWinSystem == WindowingSystem::XCB)
{
return CreateXCBWindowingData(m_XCBConnection, (xcb_window_t)window->winId()); return CreateXCBWindowingData(m_XCBConnection, (xcb_window_t)window->winId());
else }
else if(m_CurWinSystem == WindowingSystem::Xlib)
{
return CreateXlibWindowingData(m_X11Display, (Drawable)window->winId()); return CreateXlibWindowingData(m_X11Display, (Drawable)window->winId());
}
else
{
return CreateHeadlessWindowingData(1, 1);
}
#elif defined(RENDERDOC_PLATFORM_APPLE) #elif defined(RENDERDOC_PLATFORM_APPLE)
+1
View File
@@ -367,6 +367,7 @@ private:
WindowingSystem m_CurWinSystem = WindowingSystem::Unknown; WindowingSystem m_CurWinSystem = WindowingSystem::Unknown;
#if defined(RENDERDOC_PLATFORM_LINUX) #if defined(RENDERDOC_PLATFORM_LINUX)
wl_display *m_WaylandDisplay = NULL;
xcb_connection_t *m_XCBConnection = NULL; xcb_connection_t *m_XCBConnection = NULL;
Display *m_X11Display = NULL; Display *m_X11Display = NULL;
#endif #endif
+25
View File
@@ -2156,3 +2156,28 @@ QColor contrastingColor(const QColor &col, const QColor &defaultCol)
else else
return QColor(Qt::black); return QColor(Qt::black);
} }
// we declare this partial class to get the accessors. THIS IS DANGEROUS as the ABI is unstable and
// this is a private class. The first few functions have been stable for a while so we hope that it
// will remain so. If a stable interface is added in future like QX11Info we should definitely use
// it instead.
//
// Unfortunately we need this for Wayland, so we only ever use it when we are absolutely forced to
// because we're running under the Wayland Qt platform.
class QOpenGLContext;
class Q_GUI_EXPORT QPlatformNativeInterface : public QObject
{
Q_OBJECT
public:
virtual void *nativeResourceForIntegration(const QByteArray &resource);
virtual void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context);
virtual void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen);
virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window);
};
void *AccessWaylandPlatformInterface(const QByteArray &resource, QWindow *window)
{
QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface();
return native->nativeResourceForWindow(resource, window);
}
+2
View File
@@ -609,3 +609,5 @@ bool IsDarkTheme();
float getLuminance(const QColor &col); float getLuminance(const QColor &col);
QColor contrastingColor(const QColor &col, const QColor &defaultCol); QColor contrastingColor(const QColor &col, const QColor &defaultCol);
void *AccessWaylandPlatformInterface(const QByteArray &resource, QWindow *window);
+1
View File
@@ -75,6 +75,7 @@
%typemap(in) Display* = HWND; %typemap(in) Display* = HWND;
%typemap(in) xcb_connection_t* = HWND; %typemap(in) xcb_connection_t* = HWND;
%typemap(in) wl_surface* = HWND;
// completely ignore rdcdatetime, we custom convert to/from a native python datetime // completely ignore rdcdatetime, we custom convert to/from a native python datetime
%ignore rdcdatetime; %ignore rdcdatetime;
+14
View File
@@ -358,6 +358,20 @@ int main(int argc, char *argv[])
GlobalEnvironment env; GlobalEnvironment env;
#if defined(RENDERDOC_PLATFORM_LINUX) #if defined(RENDERDOC_PLATFORM_LINUX)
env.xlibDisplay = QX11Info::display(); env.xlibDisplay = QX11Info::display();
if(QGuiApplication::platformName() == lit("wayland"))
{
env.waylandDisplay = (wl_display *)AccessWaylandPlatformInterface("display", NULL);
QString warning =
tr("Running directly on Wayland is NOT SUPPORTED and is likely to crash, hang, or "
"fail to render.");
qInfo() << "------ !!!! WARNING !!!! ------";
qInfo() << warning;
qInfo() << "------ !!!! WARNING !!!! ------";
RDDialog::critical(NULL, tr("Wayland Qt platform not supported"), warning);
}
#endif #endif
rdcarray<rdcstr> coreargs; rdcarray<rdcstr> coreargs;
if(!crashReportPath.isEmpty()) if(!crashReportPath.isEmpty())
+10
View File
@@ -70,6 +70,16 @@ elseif(UNIX)
list(APPEND RDOC_LIBRARIES list(APPEND RDOC_LIBRARIES
PRIVATE -l${XCB_LIBRARIES}) PRIVATE -l${XCB_LIBRARIES})
endif() endif()
if(ENABLE_WAYLAND)
pkg_check_modules(PKG_WAYLAND QUIET wayland-client)
list(APPEND RDOC_INCLUDES
PRIVATE ${PKG_WAYLAND_INCLUDE_DIRS})
list(APPEND RDOC_LIBRARIES
PRIVATE -l${PKG_WAYLAND_LIBRARIES})
endif()
endif() endif()
if(NOT "x${CMAKE_THREAD_LIBS_INIT}" STREQUAL "x") if(NOT "x${CMAKE_THREAD_LIBS_INIT}" STREQUAL "x")
+37
View File
@@ -330,6 +330,10 @@ DOCUMENT(R"(Specifies a windowing system to use for creating an output window.
The windowing data refers to an XCB window. See :func:`CreateXCBWindowingData`. The windowing data refers to an XCB window. See :func:`CreateXCBWindowingData`.
.. data:: Wayland
The windowing data refers to an Wayland window. See :func:`CreateWaylandWindowingData`.
.. data:: Android .. data:: Android
The windowing data refers to an Android window. See :func:`CreateAndroidWindowingData`. The windowing data refers to an Android window. See :func:`CreateAndroidWindowingData`.
@@ -349,6 +353,7 @@ enum class WindowingSystem : uint32_t
Android, Android,
MacOS, MacOS,
GGP, GGP,
Wayland,
}; };
DECLARE_REFLECTION_ENUM(WindowingSystem); DECLARE_REFLECTION_ENUM(WindowingSystem);
@@ -368,6 +373,10 @@ typedef unsigned long Drawable;
struct xcb_connection_t; struct xcb_connection_t;
typedef uint32_t xcb_window_t; typedef uint32_t xcb_window_t;
// wayland
struct wl_display;
struct wl_surface;
// android // android
struct ANativeWindow; struct ANativeWindow;
@@ -409,6 +418,12 @@ struct WindowingData
xcb_window_t window; xcb_window_t window;
} xcb; } xcb;
struct
{
wl_display *display;
wl_surface *window;
} wayland;
struct struct
{ {
ANativeWindow *window; ANativeWindow *window;
@@ -498,6 +513,24 @@ inline const WindowingData CreateXCBWindowingData(xcb_connection_t *connection,
return ret; return ret;
} }
DOCUMENT(R"(Create a :class:`WindowingData` for an Wayland ``wl_surface`` handle.
:param wl_display display: The ``wl_display`` connection used for this window.
:param wl_surface window: The native ``wl_surface`` handle for this window.
:return: A :class:`WindowingData` corresponding to the given window.
:rtype: WindowingData
)");
inline const WindowingData CreateWaylandWindowingData(wl_display *display, wl_surface *window)
{
WindowingData ret = {};
ret.system = WindowingSystem::Wayland;
ret.wayland.display = display;
ret.wayland.window = window;
return ret;
}
DOCUMENT(R"(Create a :class:`WindowingData` for a GGP application. DOCUMENT(R"(Create a :class:`WindowingData` for a GGP application.
:return: A :class:`WindowingData` corresponding to the given system. :return: A :class:`WindowingData` corresponding to the given system.
@@ -571,6 +604,10 @@ struct GlobalEnvironment
DOCUMENT("The handle to the X display to use internally. If left ``NULL``, one will be opened."); DOCUMENT("The handle to the X display to use internally. If left ``NULL``, one will be opened.");
Display *xlibDisplay = NULL; Display *xlibDisplay = NULL;
DOCUMENT(
"The handle to the X display to use internally. If left ``NULL``, wayland cannot be used.");
wl_display *waylandDisplay = NULL;
}; };
DOCUMENT("The result of executing or injecting into a program.") DOCUMENT("The result of executing or injecting into a program.")
+3
View File
@@ -60,11 +60,14 @@ rdcstr DoStringise(const WindowingSystem &el)
BEGIN_ENUM_STRINGISE(WindowingSystem) BEGIN_ENUM_STRINGISE(WindowingSystem)
{ {
STRINGISE_ENUM_CLASS(Unknown); STRINGISE_ENUM_CLASS(Unknown);
STRINGISE_ENUM_CLASS(Headless);
STRINGISE_ENUM_CLASS(Win32); STRINGISE_ENUM_CLASS(Win32);
STRINGISE_ENUM_CLASS(Xlib); STRINGISE_ENUM_CLASS(Xlib);
STRINGISE_ENUM_CLASS(XCB); STRINGISE_ENUM_CLASS(XCB);
STRINGISE_ENUM_CLASS(Android); STRINGISE_ENUM_CLASS(Android);
STRINGISE_ENUM_CLASS(MacOS); STRINGISE_ENUM_CLASS(MacOS);
STRINGISE_ENUM_CLASS(GGP);
STRINGISE_ENUM_CLASS(Wayland);
} }
END_ENUM_STRINGISE(); END_ENUM_STRINGISE();
} }
+6
View File
@@ -129,6 +129,12 @@
#define RDOC_XCB OPTION_OFF #define RDOC_XCB OPTION_OFF
#endif #endif
#if defined(RENDERDOC_WINDOWING_WAYLAND)
#define RDOC_WAYLAND OPTION_ON
#else
#define RDOC_WAYLAND OPTION_OFF
#endif
///////////////////////////////////////////////// /////////////////////////////////////////////////
// Global constants // Global constants
enum enum
+2 -2
View File
@@ -1323,7 +1323,7 @@ void WrappedID3D11Device::ReleaseSwapchainResources(IDXGISwapper *swapper, UINT
if(wnd) if(wnd)
{ {
Keyboard::RemoveInputWindow(wnd); Keyboard::RemoveInputWindow(WindowingSystem::Win32, wnd);
RenderDoc::Inst().RemoveFrameCapturer((ID3D11Device *)this, wnd); RenderDoc::Inst().RemoveFrameCapturer((ID3D11Device *)this, wnd);
} }
@@ -1460,7 +1460,7 @@ IUnknown *WrappedID3D11Device::WrapSwapchainBuffer(IDXGISwapper *swapper, DXGI_F
if(wnd) if(wnd)
{ {
Keyboard::AddInputWindow(wnd); Keyboard::AddInputWindow(WindowingSystem::Win32, wnd);
RenderDoc::Inst().AddFrameCapturer((ID3D11Device *)this, wnd, this); RenderDoc::Inst().AddFrameCapturer((ID3D11Device *)this, wnd, this);
} }
+2 -2
View File
@@ -870,7 +870,7 @@ void WrappedID3D12Device::ReleaseSwapchainResources(IDXGISwapper *swapper, UINT
if(wnd) if(wnd)
{ {
Keyboard::RemoveInputWindow(wnd); Keyboard::RemoveInputWindow(WindowingSystem::Win32, wnd);
RenderDoc::Inst().RemoveFrameCapturer((ID3D12Device *)this, wnd); RenderDoc::Inst().RemoveFrameCapturer((ID3D12Device *)this, wnd);
} }
@@ -1045,7 +1045,7 @@ IUnknown *WrappedID3D12Device::WrapSwapchainBuffer(IDXGISwapper *swapper, DXGI_F
if(wnd) if(wnd)
{ {
Keyboard::AddInputWindow(wnd); Keyboard::AddInputWindow(WindowingSystem::Win32, wnd);
RenderDoc::Inst().AddFrameCapturer((ID3D12Device *)this, wnd, this); RenderDoc::Inst().AddFrameCapturer((ID3D12Device *)this, wnd, this);
} }
+1 -1
View File
@@ -178,7 +178,7 @@ CGLError GL_EXPORT_NAME(CGLFlushDrawable)(CGLContextObj ctx)
CGL.CGLGetSurface(ctx, &conn, &window, &surface); CGL.CGLGetSurface(ctx, &conn, &window, &surface);
cglhook.driver.SwapBuffers((void *)(uintptr_t)window); cglhook.driver.SwapBuffers(WindowingSystem::macOS, (void *)(uintptr_t)window);
} }
CGLError ret; CGLError ret;
+18 -11
View File
@@ -28,6 +28,8 @@
typedef EGLBoolean(EGLAPIENTRY *PFN_eglBindAPI)(EGLenum api); typedef EGLBoolean(EGLAPIENTRY *PFN_eglBindAPI)(EGLenum api);
typedef EGLDisplay(EGLAPIENTRY *PFN_eglGetDisplay)(EGLNativeDisplayType display_id); typedef EGLDisplay(EGLAPIENTRY *PFN_eglGetDisplay)(EGLNativeDisplayType display_id);
typedef EGLDisplay(EGLAPIENTRY *PFN_eglGetPlatformDisplay)(EGLenum platform, void *native_display,
const EGLAttrib *attrib_list);
typedef EGLContext(EGLAPIENTRY *PFN_eglCreateContext)(EGLDisplay dpy, EGLConfig config, typedef EGLContext(EGLAPIENTRY *PFN_eglCreateContext)(EGLDisplay dpy, EGLConfig config,
EGLContext share_context, EGLContext share_context,
const EGLint *attrib_list); const EGLint *attrib_list);
@@ -43,6 +45,9 @@ typedef EGLSurface(EGLAPIENTRY *PFN_eglCreatePbufferSurface)(EGLDisplay dpy, EGL
typedef EGLSurface(EGLAPIENTRY *PFN_eglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, typedef EGLSurface(EGLAPIENTRY *PFN_eglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config,
EGLNativeWindowType win, EGLNativeWindowType win,
const EGLint *attrib_list); const EGLint *attrib_list);
typedef EGLSurface(EGLAPIENTRY *PFN_eglCreatePlatformWindowSurface)(EGLDisplay dpy, EGLConfig config,
void *native_window,
const EGLAttrib *attrib_list);
typedef EGLBoolean(EGLAPIENTRY *PFN_eglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, typedef EGLBoolean(EGLAPIENTRY *PFN_eglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list,
EGLConfig *configs, EGLint config_size, EGLConfig *configs, EGLint config_size,
EGLint *num_config); EGLint *num_config);
@@ -60,17 +65,19 @@ typedef PFNEGLPOSTSUBBUFFERNVPROC PFN_eglPostSubBufferNV;
typedef PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC PFN_eglSwapBuffersWithDamageEXT; typedef PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC PFN_eglSwapBuffersWithDamageEXT;
typedef PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC PFN_eglSwapBuffersWithDamageKHR; typedef PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC PFN_eglSwapBuffersWithDamageKHR;
#define EGL_HOOKED_SYMBOLS(FUNC) \ #define EGL_HOOKED_SYMBOLS(FUNC) \
FUNC(BindAPI, false); \ FUNC(BindAPI, false); \
FUNC(GetProcAddress, false); \ FUNC(GetProcAddress, false); \
FUNC(GetDisplay, false); \ FUNC(GetDisplay, false); \
FUNC(CreateContext, false); \ FUNC(GetPlatformDisplay, false); \
FUNC(DestroyContext, false); \ FUNC(CreateContext, false); \
FUNC(CreateWindowSurface, false); \ FUNC(DestroyContext, false); \
FUNC(MakeCurrent, false); \ FUNC(CreateWindowSurface, false); \
FUNC(SwapBuffers, false); \ FUNC(CreatePlatformWindowSurface, false); \
FUNC(PostSubBufferNV, true); \ FUNC(MakeCurrent, false); \
FUNC(SwapBuffersWithDamageEXT, true); \ FUNC(SwapBuffers, false); \
FUNC(PostSubBufferNV, true); \
FUNC(SwapBuffersWithDamageEXT, true); \
FUNC(SwapBuffersWithDamageKHR, true); FUNC(SwapBuffersWithDamageKHR, true);
#define EGL_NONHOOKED_SYMBOLS(FUNC) \ #define EGL_NONHOOKED_SYMBOLS(FUNC) \
+114 -17
View File
@@ -38,10 +38,23 @@
#if ENABLED(RDOC_LINUX) #if ENABLED(RDOC_LINUX)
namespace Keyboard namespace Keyboard
{ {
void CloneDisplay(Display *dpy); void UseXlibDisplay(Display *dpy);
WindowingSystem UseUnknownDisplay(void *disp);
void UseWaylandDisplay(wl_display *disp);
} }
#endif #endif
struct SurfaceConfig
{
WindowingSystem system;
void *wnd;
};
struct DisplayConfig
{
WindowingSystem system;
};
class EGLHook : LibraryHook class EGLHook : LibraryHook
{ {
public: public:
@@ -54,7 +67,8 @@ public:
WrappedOpenGL driver; WrappedOpenGL driver;
std::set<EGLContext> contexts; std::set<EGLContext> contexts;
std::map<EGLContext, EGLConfig> configs; std::map<EGLContext, EGLConfig> configs;
std::map<EGLSurface, EGLNativeWindowType> windows; std::map<EGLSurface, SurfaceConfig> windows;
std::map<EGLDisplay, DisplayConfig> displays;
// indicates we're in a swap function, so don't process the swap any further if we recurse - could // indicates we're in a swap function, so don't process the swap any further if we recurse - could
// happen due to driver implementation of one function calling another // happen due to driver implementation of one function calling another
@@ -121,12 +135,15 @@ static void EnsureRealLibraryLoaded()
#if ENABLED(RDOC_LINUX) #if ENABLED(RDOC_LINUX)
if(eglhook.handle == DEFAULT_HANDLE) if(eglhook.handle == DEFAULT_HANDLE)
{ {
RDCLOG("Loading libEGL at the last second"); if(!RenderDoc::Inst().IsReplayApp())
RDCLOG("Loading libEGL at the last second");
void *handle = Process::LoadModule("libEGL.so"); void *handle = Process::LoadModule("libEGL.so");
if(!handle) if(!handle)
handle = Process::LoadModule("libEGL.so.1"); handle = Process::LoadModule("libEGL.so.1");
eglhook.handle = handle;
} }
#endif #endif
} }
@@ -144,12 +161,38 @@ HOOK_EXPORT EGLDisplay EGLAPIENTRY eglGetDisplay_renderdoc_hooked(EGLNativeDispl
EnsureRealLibraryLoaded(); EnsureRealLibraryLoaded();
#if ENABLED(RDOC_LINUX) #if ENABLED(RDOC_LINUX)
Keyboard::CloneDisplay(display); Keyboard::UseUnknownDisplay((void *)display);
#endif #endif
return EGL.GetDisplay(display); return EGL.GetDisplay(display);
} }
HOOK_EXPORT EGLDisplay EGLAPIENTRY eglGetPlatformDisplay_renderdoc_hooked(EGLenum platform,
void *native_display,
const EGLAttrib *attrib_list)
{
if(RenderDoc::Inst().IsReplayApp())
{
if(!EGL.GetDisplay)
EGL.PopulateForReplay();
return EGL.GetPlatformDisplay(platform, native_display, attrib_list);
}
EnsureRealLibraryLoaded();
#if ENABLED(RDOC_LINUX)
if(platform == EGL_PLATFORM_X11_KHR)
Keyboard::UseXlibDisplay((Display *)native_display);
else if(platform == EGL_PLATFORM_WAYLAND_KHR)
Keyboard::UseWaylandDisplay((wl_display *)native_display);
else
RDCWARN("Unknown platform %x in eglGetPlatformDisplay", platform);
#endif
return EGL.GetPlatformDisplay(platform, native_display, attrib_list);
}
HOOK_EXPORT EGLBoolean EGLAPIENTRY eglBindAPI_renderdoc_hooked(EGLenum api) HOOK_EXPORT EGLBoolean EGLAPIENTRY eglBindAPI_renderdoc_hooked(EGLenum api)
{ {
if(RenderDoc::Inst().IsReplayApp()) if(RenderDoc::Inst().IsReplayApp())
@@ -336,7 +379,35 @@ HOOK_EXPORT EGLSurface EGLAPIENTRY eglCreateWindowSurface_renderdoc_hooked(EGLDi
{ {
SCOPED_LOCK(glLock); SCOPED_LOCK(glLock);
eglhook.windows[ret] = win; // spec says it's implementation dependent what happens, so we assume that we're using the same
// window system as the display
eglhook.windows[ret] = {eglhook.displays[dpy].system, (void *)win};
}
return ret;
}
HOOK_EXPORT EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurface_renderdoc_hooked(
EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list)
{
if(RenderDoc::Inst().IsReplayApp())
{
if(!EGL.CreatePlatformWindowSurface)
EGL.PopulateForReplay();
return EGL.CreatePlatformWindowSurface(dpy, config, native_window, attrib_list);
}
EnsureRealLibraryLoaded();
EGLSurface ret = EGL.CreatePlatformWindowSurface(dpy, config, native_window, attrib_list);
if(ret)
{
SCOPED_LOCK(glLock);
// spec guarantees that we're using the same window system as the display
eglhook.windows[ret] = {eglhook.displays[dpy].system, native_window};
} }
return ret; return ret;
@@ -376,17 +447,20 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglMakeCurrent_renderdoc_hooked(EGLDisplay di
GL.DriverForEmulation(&eglhook.driver); GL.DriverForEmulation(&eglhook.driver);
} }
SurfaceConfig cfg = eglhook.windows[draw];
GLWindowingData data; GLWindowingData data;
data.egl_dpy = display; data.egl_dpy = display;
data.egl_wnd = draw; data.egl_wnd = draw;
data.egl_ctx = ctx; data.egl_ctx = ctx;
data.wnd = (decltype(data.wnd))eglhook.windows[draw]; data.wnd = (decltype(data.wnd))cfg.wnd;
if(!data.wnd) if(!data.wnd)
{ {
// could be a pbuffer surface or other offscreen rendering. We want a valid wnd, so set it to // could be a pbuffer surface or other offscreen rendering. We want a valid wnd, so set it to
// a dummy value // a dummy value
data.wnd = (decltype(data.wnd))(void *)(uintptr_t(0xdeadbeef) + uintptr_t(draw)); data.wnd = (decltype(data.wnd))(void *)(uintptr_t(0xdeadbeef) + uintptr_t(draw));
cfg.system = WindowingSystem::Headless;
} }
// we could query this out technically but it's easier to keep a map // we could query this out technically but it's easier to keep a map
@@ -426,7 +500,9 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffers_renderdoc_hooked(EGLDisplay dp
eglhook.RefreshWindowParameters(data); eglhook.RefreshWindowParameters(data);
eglhook.driver.SwapBuffers(surface); SurfaceConfig cfg = eglhook.windows[surface];
eglhook.driver.SwapBuffers(cfg.system, cfg.wnd);
} }
{ {
@@ -456,7 +532,11 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglPostSubBufferNV_renderdoc_hooked(EGLDispla
eglhook.driver.SetDriverType(eglhook.activeAPI); eglhook.driver.SetDriverType(eglhook.activeAPI);
if(!eglhook.driver.UsesVRFrameMarkers() && !eglhook.swapping) if(!eglhook.driver.UsesVRFrameMarkers() && !eglhook.swapping)
eglhook.driver.SwapBuffers((void *)eglhook.windows[surface]); {
SurfaceConfig cfg = eglhook.windows[surface];
eglhook.driver.SwapBuffers(cfg.system, cfg.wnd);
}
{ {
eglhook.swapping = true; eglhook.swapping = true;
@@ -485,7 +565,11 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageEXT_renderdoc_hooked(
eglhook.driver.SetDriverType(eglhook.activeAPI); eglhook.driver.SetDriverType(eglhook.activeAPI);
if(!eglhook.driver.UsesVRFrameMarkers() && !eglhook.swapping) if(!eglhook.driver.UsesVRFrameMarkers() && !eglhook.swapping)
eglhook.driver.SwapBuffers((void *)eglhook.windows[surface]); {
SurfaceConfig cfg = eglhook.windows[surface];
eglhook.driver.SwapBuffers(cfg.system, cfg.wnd);
}
{ {
eglhook.swapping = true; eglhook.swapping = true;
@@ -514,7 +598,11 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageKHR_renderdoc_hooked(
eglhook.driver.SetDriverType(eglhook.activeAPI); eglhook.driver.SetDriverType(eglhook.activeAPI);
if(!eglhook.driver.UsesVRFrameMarkers() && !eglhook.swapping) if(!eglhook.driver.UsesVRFrameMarkers() && !eglhook.swapping)
eglhook.driver.SwapBuffers((void *)eglhook.windows[surface]); {
SurfaceConfig cfg = eglhook.windows[surface];
eglhook.driver.SwapBuffers(cfg.system, cfg.wnd);
}
{ {
eglhook.swapping = true; eglhook.swapping = true;
@@ -549,9 +637,9 @@ eglGetProcAddress_renderdoc_hooked(const char *func)
return realFunc; return realFunc;
// return our egl hooks // return our egl hooks
#define GPA_FUNCTION(name) \ #define GPA_FUNCTION(name, isext) \
if(!strcmp(func, "egl" STRINGIZE(name))) \ if(!strcmp(func, "egl" STRINGIZE(name))) \
return (__eglMustCastToProperFunctionPointerType)&CONCAT(egl, CONCAT(name, _renderdoc_hooked)); \ return (__eglMustCastToProperFunctionPointerType)&CONCAT(egl, CONCAT(name, _renderdoc_hooked));
EGL_HOOKED_SYMBOLS(GPA_FUNCTION) EGL_HOOKED_SYMBOLS(GPA_FUNCTION)
#undef GPA_FUNCTION #undef GPA_FUNCTION
@@ -578,6 +666,12 @@ HOOK_EXPORT EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display)
return eglGetDisplay_renderdoc_hooked(display); return eglGetDisplay_renderdoc_hooked(display);
} }
HOOK_EXPORT EGLDisplay EGLAPIENTRY eglGetPlatformDisplay(EGLenum platform, void *native_display,
const EGLAttrib *attrib_list)
{
return eglGetPlatformDisplay_renderdoc_hooked(platform, native_display, attrib_list);
}
HOOK_EXPORT EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay display, EGLConfig config, HOOK_EXPORT EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay display, EGLConfig config,
EGLContext shareContext, EGLint const *attribList) EGLContext shareContext, EGLint const *attribList)
{ {
@@ -596,6 +690,13 @@ HOOK_EXPORT EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLCon
return eglCreateWindowSurface_renderdoc_hooked(dpy, config, win, attrib_list); return eglCreateWindowSurface_renderdoc_hooked(dpy, config, win, attrib_list);
} }
HOOK_EXPORT EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config,
void *native_window,
const EGLAttrib *attrib_list)
{
return eglCreatePlatformWindowSurface_renderdoc_hooked(dpy, config, native_window, attrib_list);
}
HOOK_EXPORT EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay display, EGLSurface draw, HOOK_EXPORT EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay display, EGLSurface draw,
EGLSurface read, EGLContext ctx) EGLSurface read, EGLContext ctx)
{ {
@@ -757,10 +858,6 @@ EGL_PASSTHRU_4(EGLBoolean, eglGetSyncAttrib, EGLDisplay, dpy, EGLSync, sync, EGL
EGL_PASSTHRU_5(EGLImage, eglCreateImage, EGLDisplay, dpy, EGLContext, ctx, EGLenum, target, EGL_PASSTHRU_5(EGLImage, eglCreateImage, EGLDisplay, dpy, EGLContext, ctx, EGLenum, target,
EGLClientBuffer, buffer, const EGLAttrib *, attrib_list) EGLClientBuffer, buffer, const EGLAttrib *, attrib_list)
EGL_PASSTHRU_2(EGLBoolean, eglDestroyImage, EGLDisplay, dpy, EGLImage, image) EGL_PASSTHRU_2(EGLBoolean, eglDestroyImage, EGLDisplay, dpy, EGLImage, image)
EGL_PASSTHRU_3(EGLDisplay, eglGetPlatformDisplay, EGLenum, platform, void *, native_display,
const EGLAttrib *, attrib_list)
EGL_PASSTHRU_4(EGLSurface, eglCreatePlatformWindowSurface, EGLDisplay, dpy, EGLConfig, config,
void *, native_window, const EGLAttrib *, attrib_list)
EGL_PASSTHRU_4(EGLSurface, eglCreatePlatformPixmapSurface, EGLDisplay, dpy, EGLConfig, config, EGL_PASSTHRU_4(EGLSurface, eglCreatePlatformPixmapSurface, EGLDisplay, dpy, EGLConfig, config,
void *, native_pixmap, const EGLAttrib *, attrib_list) void *, native_pixmap, const EGLAttrib *, attrib_list)
EGL_PASSTHRU_3(EGLBoolean, eglWaitSync, EGLDisplay, dpy, EGLSync, sync, EGLint, flags) EGL_PASSTHRU_3(EGLBoolean, eglWaitSync, EGLDisplay, dpy, EGLSync, sync, EGLint, flags)
+77 -23
View File
@@ -42,6 +42,8 @@ static void *GetEGLHandle()
class EGLPlatform : public GLPlatform class EGLPlatform : public GLPlatform
{ {
RDCDriver m_API = RDCDriver::OpenGLES;
bool MakeContextCurrent(GLWindowingData data) bool MakeContextCurrent(GLWindowingData data)
{ {
if(EGL.MakeCurrent) if(EGL.MakeCurrent)
@@ -113,6 +115,7 @@ class EGLPlatform : public GLPlatform
bool IsOutputWindowVisible(GLWindowingData context) { return true; } bool IsOutputWindowVisible(GLWindowingData context) { return true; }
GLWindowingData MakeOutputWindow(WindowingData window, bool depth, GLWindowingData share_context) GLWindowingData MakeOutputWindow(WindowingData window, bool depth, GLWindowingData share_context)
{ {
EGLNativeDisplayType display = EGL_DEFAULT_DISPLAY;
EGLNativeWindowType win = 0; EGLNativeWindowType win = 0;
switch(window.system) switch(window.system)
@@ -122,7 +125,32 @@ class EGLPlatform : public GLPlatform
#elif ENABLED(RDOC_ANDROID) #elif ENABLED(RDOC_ANDROID)
case WindowingSystem::Android: win = window.android.window; break; case WindowingSystem::Android: win = window.android.window; break;
#elif ENABLED(RDOC_LINUX) #elif ENABLED(RDOC_LINUX)
case WindowingSystem::Xlib: win = window.xlib.window; break; case WindowingSystem::Xlib:
{
Display *xlibDisplay = RenderDoc::Inst().GetGlobalEnvironment().xlibDisplay;
display = (EGLNativeDisplayType)window.xlib.display;
win = (EGLNativeWindowType)window.xlib.window;
// ensure we're using the same display as the share context, and the same as our global
// display that we used at init time to create the share context's display
RDCASSERT((void *)display == (void *)xlibDisplay && display != NULL, (void *)display,
(void *)xlibDisplay);
break;
}
case WindowingSystem::Wayland:
{
wl_display *waylandDisplay = RenderDoc::Inst().GetGlobalEnvironment().waylandDisplay;
display = (EGLNativeDisplayType)window.wayland.display;
win = (EGLNativeWindowType)window.wayland.window;
// ensure we're using the same display as the share context, and the same as our global
// display
RDCASSERT((void *)display == (void *)waylandDisplay && display != NULL, (void *)display,
(void *)waylandDisplay);
break;
}
#endif #endif
case WindowingSystem::Unknown: case WindowingSystem::Unknown:
case WindowingSystem::Headless: case WindowingSystem::Headless:
@@ -131,9 +159,18 @@ class EGLPlatform : public GLPlatform
default: RDCERR("Unexpected window system %u", window.system); break; default: RDCERR("Unexpected window system %u", window.system); break;
} }
EGLDisplay eglDisplay = EGL.GetDisplay(EGL_DEFAULT_DISPLAY); EGLDisplay eglDisplay = NULL;
if(share_context.egl_dpy)
eglDisplay = share_context.egl_dpy;
else
eglDisplay = EGL.GetDisplay(display);
RDCASSERT(eglDisplay); RDCASSERT(eglDisplay);
int major, minor;
EGL.Initialize(eglDisplay, &major, &minor);
return CreateWindowingData(eglDisplay, share_context.ctx, win, false); return CreateWindowingData(eglDisplay, share_context.ctx, win, false);
} }
@@ -150,24 +187,27 @@ class EGLPlatform : public GLPlatform
ret.egl_wnd = NULL; ret.egl_wnd = NULL;
EGLint surfaceType = (window == 0) ? EGL_PBUFFER_BIT : EGL_WINDOW_BIT; EGLint surfaceType = (window == 0) ? EGL_PBUFFER_BIT : EGL_WINDOW_BIT;
const EGLint configAttribs[] = {EGL_RED_SIZE, const EGLint configAttribs[] = {
8, EGL_RED_SIZE,
EGL_GREEN_SIZE, 8,
8, EGL_GREEN_SIZE,
EGL_BLUE_SIZE, 8,
8, EGL_BLUE_SIZE,
EGL_RENDERABLE_TYPE, 8,
EGL_OPENGL_ES3_BIT, EGL_RENDERABLE_TYPE,
EGL_CONFORMANT, m_API == RDCDriver::OpenGLES ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_BIT,
EGL_OPENGL_ES3_BIT, EGL_CONFORMANT,
EGL_SURFACE_TYPE, m_API == RDCDriver::OpenGLES ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_BIT,
surfaceType, EGL_SURFACE_TYPE,
EGL_COLOR_BUFFER_TYPE, surfaceType,
EGL_RGB_BUFFER, EGL_COLOR_BUFFER_TYPE,
EGL_NONE}; EGL_RGB_BUFFER,
EGL_NONE,
};
EGLint numConfigs; EGLint numConfigs = 0;
if(!EGL.ChooseConfig(eglDisplay, configAttribs, &ret.egl_cfg, 1, &numConfigs)) EGLBoolean success = EGL.ChooseConfig(eglDisplay, configAttribs, &ret.egl_cfg, 1, &numConfigs);
if(!success || numConfigs == 0)
{ {
RDCERR("Couldn't find a suitable EGL config"); RDCERR("Couldn't find a suitable EGL config");
return ret; return ret;
@@ -280,12 +320,26 @@ class EGLPlatform : public GLPlatform
bool PopulateForReplay() { return EGL.PopulateForReplay(); } bool PopulateForReplay() { return EGL.PopulateForReplay(); }
ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api, bool debug) ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api, bool debug)
{ {
// we only support replaying GLES through EGL Display *xlibDisplay = RenderDoc::Inst().GetGlobalEnvironment().xlibDisplay;
RDCASSERT(api == RDCDriver::OpenGLES); wl_display *waylandDisplay = RenderDoc::Inst().GetGlobalEnvironment().waylandDisplay;
EGL.BindAPI(EGL_OPENGL_ES_API); // we only support replaying GLES through EGL, except if Wayland is enabled
RDCASSERT(api == RDCDriver::OpenGLES || waylandDisplay);
EGLDisplay eglDisplay = EGL.GetDisplay(EGL_DEFAULT_DISPLAY); m_API = api;
if(api == RDCDriver::OpenGLES)
EGL.BindAPI(EGL_OPENGL_ES_API);
else
EGL.BindAPI(EGL_OPENGL_API);
EGLNativeDisplayType display = EGL_DEFAULT_DISPLAY;
if(waylandDisplay)
display = (EGLNativeDisplayType)waylandDisplay;
else if(xlibDisplay)
display = (EGLNativeDisplayType)xlibDisplay;
EGLDisplay eglDisplay = EGL.GetDisplay(display);
if(!eglDisplay) if(!eglDisplay)
{ {
RDCERR("Couldn't open default EGL display"); RDCERR("Couldn't open default EGL display");
+6 -1
View File
@@ -340,9 +340,14 @@ void GLReplay::InitDebugData()
RenderDoc::Inst().SetProgress(LoadProgress::DebugManagerInit, 0.0f); RenderDoc::Inst().SetProgress(LoadProgress::DebugManagerInit, 0.0f);
{ {
WindowingData window = {WindowingSystem::Unknown}; WindowingData window = {WindowingSystem::Headless};
uint64_t id = MakeOutputWindow(window, true); uint64_t id = MakeOutputWindow(window, true);
m_DebugCtx = NULL;
if(id == 0)
return;
m_DebugID = id; m_DebugID = id;
m_DebugCtx = &m_OutputWindows[id]; m_DebugCtx = &m_OutputWindows[id];
+18 -14
View File
@@ -1061,29 +1061,38 @@ void WrappedOpenGL::DeleteContext(void *contextHandle)
void *wndHandle = it->first; void *wndHandle = it->first;
it++; it++;
ctxdata.UnassociateWindow(wndHandle); ctxdata.UnassociateWindow(this, wndHandle);
} }
m_ContextData.erase(contextHandle); m_ContextData.erase(contextHandle);
} }
void WrappedOpenGL::ContextData::UnassociateWindow(void *wndHandle) void WrappedOpenGL::ContextData::UnassociateWindow(WrappedOpenGL *driver, void *wndHandle)
{ {
auto it = windows.find(wndHandle); auto it = windows.find(wndHandle);
if(it != windows.end()) if(it != windows.end())
{ {
if(it->second.first != WindowingSystem::Headless && IsCaptureMode(driver->GetState()))
Keyboard::RemoveInputWindow(it->second.first, wndHandle);
windows.erase(wndHandle); windows.erase(wndHandle);
RenderDoc::Inst().RemoveFrameCapturer(ctx, wndHandle); RenderDoc::Inst().RemoveFrameCapturer(ctx, wndHandle);
} }
} }
void WrappedOpenGL::ContextData::AssociateWindow(WrappedOpenGL *driver, void *wndHandle) void WrappedOpenGL::ContextData::AssociateWindow(WrappedOpenGL *driver, WindowingSystem winSystem,
void *wndHandle)
{ {
auto it = windows.find(wndHandle); auto it = windows.find(wndHandle);
if(it == windows.end()) if(it == windows.end())
{
RenderDoc::Inst().AddFrameCapturer(ctx, wndHandle, driver); RenderDoc::Inst().AddFrameCapturer(ctx, wndHandle, driver);
windows[wndHandle] = Timing::GetUnixTimestamp(); if(winSystem != WindowingSystem::Headless && IsCaptureMode(driver->GetState()))
Keyboard::AddInputWindow(winSystem, wndHandle);
}
windows[wndHandle] = {winSystem, Timing::GetUnixTimestamp()};
} }
void WrappedOpenGL::ContextData::CreateResourceRecord(WrappedOpenGL *driver, void *suppliedCtx) void WrappedOpenGL::ContextData::CreateResourceRecord(WrappedOpenGL *driver, void *suppliedCtx)
@@ -1245,9 +1254,6 @@ void WrappedOpenGL::ActivateContext(GLWindowingData winData)
m_LastContexts.erase(m_LastContexts.begin()); m_LastContexts.erase(m_LastContexts.begin());
} }
// TODO: support multiple GL contexts more explicitly
Keyboard::AddInputWindow((void *)winData.wnd);
if(winData.ctx) if(winData.ctx)
{ {
if(IsActiveCapturing(m_State)) if(IsActiveCapturing(m_State))
@@ -1802,7 +1808,7 @@ void WrappedOpenGL::FreeTargetResource(ResourceId id)
} }
} }
void WrappedOpenGL::SwapBuffers(void *windowHandle) void WrappedOpenGL::SwapBuffers(WindowingSystem winSystem, void *windowHandle)
{ {
if(IsBackgroundCapturing(m_State)) if(IsBackgroundCapturing(m_State))
RenderDoc::Inst().Tick(); RenderDoc::Inst().Tick();
@@ -1840,9 +1846,9 @@ void WrappedOpenGL::SwapBuffers(void *windowHandle)
{ {
for(auto it = m_ContextData.begin(); it != m_ContextData.end(); ++it) for(auto it = m_ContextData.begin(); it != m_ContextData.end(); ++it)
if(it->first != ctxdata.ctx) if(it->first != ctxdata.ctx)
it->second.UnassociateWindow(windowHandle); it->second.UnassociateWindow(this, windowHandle);
ctxdata.AssociateWindow(this, windowHandle); ctxdata.AssociateWindow(this, winSystem, windowHandle);
} }
// we used to do this here so it was as late as possible to avoid creating objects on contexts // we used to do this here so it was as late as possible to avoid creating objects on contexts
@@ -1863,14 +1869,12 @@ void WrappedOpenGL::SwapBuffers(void *windowHandle)
{ {
for(auto wit = cit->second.windows.begin(); wit != cit->second.windows.end();) for(auto wit = cit->second.windows.begin(); wit != cit->second.windows.end();)
{ {
if(wit->second < ref) if(wit->second.second < ref)
{ {
auto remove = wit; auto remove = wit;
++wit; ++wit;
RenderDoc::Inst().RemoveFrameCapturer(cit->first, remove->first); cit->second.UnassociateWindow(this, remove->first);
cit->second.windows.erase(remove);
} }
else else
{ {
+8 -8
View File
@@ -359,17 +359,17 @@ private:
GLInitParams initParams; GLInitParams initParams;
// map from window handle void* to uint64_t unix timestamp with // map from window handle void* to the windowing system used and the uint64_t unix timestamp of
// the last time a window was seen/associated with this context. // the last time a window was seen/associated with this context. Decays after a few seconds
// Decays after a few seconds since there's no good explicit // since there's no good explicit 'remove' type call for GL, only
// 'remove' type call for GL, only wglCreateContext/wglMakeCurrent // wglCreateContext/wglMakeCurrent
std::map<void *, uint64_t> windows; std::map<void *, rdcpair<WindowingSystem, uint64_t>> windows;
// a window is only associated with one context at once, so any // a window is only associated with one context at once, so any
// time we associate a window, it broadcasts to all other // time we associate a window, it broadcasts to all other
// contexts to let them know to remove it // contexts to let them know to remove it
void UnassociateWindow(void *wndHandle); void UnassociateWindow(WrappedOpenGL *driver, void *wndHandle);
void AssociateWindow(WrappedOpenGL *driver, void *wndHandle); void AssociateWindow(WrappedOpenGL *driver, WindowingSystem winSystem, void *wndHandle);
void CreateDebugData(); void CreateDebugData();
@@ -595,7 +595,7 @@ public:
} }
void ActivateContext(GLWindowingData winData); void ActivateContext(GLWindowingData winData);
bool ForceSharedObjects(void *oldContext, void *newContext); bool ForceSharedObjects(void *oldContext, void *newContext);
void SwapBuffers(void *windowHandle); void SwapBuffers(WindowingSystem winSystem, void *windowHandle);
void HandleVRFrameMarkers(const GLchar *buf, GLsizei length); void HandleVRFrameMarkers(const GLchar *buf, GLsizei length);
bool UsesVRFrameMarkers() { return m_UsesVRMarkers; } bool UsesVRFrameMarkers() { return m_UsesVRMarkers; }
void FirstFrame(void *ctx, void *wndHandle); void FirstFrame(void *ctx, void *wndHandle);
+60 -28
View File
@@ -140,12 +140,24 @@ std::vector<WindowingSystem> GLReplay::GetSupportedWindowSystems()
std::vector<WindowingSystem> ret; std::vector<WindowingSystem> ret;
#if ENABLED(RDOC_LINUX) #if ENABLED(RDOC_LINUX)
// 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 #if ENABLED(RDOC_WAYLAND)
// free to use XCB internally but it would have to create a hybrid and // if wayland is supported and a display is configured, we *must* get wayland surfaces to render
// initialise XCB out of Xlib, to be able to provide the display and // on
// drawable to us. if(RenderDoc::Inst().GetGlobalEnvironment().waylandDisplay)
ret.push_back(WindowingSystem::Xlib); {
ret.push_back(WindowingSystem::Wayland);
}
else
#endif
{
// 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(WindowingSystem::Xlib);
}
#elif ENABLED(RDOC_ANDROID) #elif ENABLED(RDOC_ANDROID)
ret.push_back(WindowingSystem::Android); ret.push_back(WindowingSystem::Android);
#elif ENABLED(RDOC_APPLE) #elif ENABLED(RDOC_APPLE)
@@ -250,6 +262,9 @@ void GLReplay::SetReplayData(GLWindowingData data)
InitDebugData(); InitDebugData();
if(!HasDebugContext())
return;
AMDCounters *countersAMD = NULL; AMDCounters *countersAMD = NULL;
IntelGlCounters *countersIntel = NULL; IntelGlCounters *countersIntel = NULL;
@@ -3465,6 +3480,12 @@ ReplayStatus CreateReplayDevice(RDCDriver rdcdriver, RDCFile *rdc, const ReplayO
replay->SetProxy(rdc == NULL); replay->SetProxy(rdc == NULL);
replay->SetReplayData(data); replay->SetReplayData(data);
if(!replay->HasDebugContext())
{
platform.DeleteReplayContext(data);
return ReplayStatus::APIHardwareUnsupported;
}
gldriver->Initialise(initParams, ver, opts); gldriver->Initialise(initParams, ver, opts);
*driver = (IReplayDriver *)replay; *driver = (IReplayDriver *)replay;
@@ -3510,28 +3531,6 @@ std::vector<GLVersion> GetReplayVersions(RDCDriver api)
} }
} }
#if defined(RENDERDOC_SUPPORT_GL)
ReplayStatus GL_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, IReplayDriver **driver)
{
RDCDEBUG("Creating an OpenGL replay device");
bool load_ok = GetGLPlatform().PopulateForReplay();
if(!load_ok)
{
RDCERR("Couldn't find required platform GL function addresses");
return ReplayStatus::APIInitFailed;
}
return CreateReplayDevice(rdc ? rdc->GetDriver() : RDCDriver::OpenGL, rdc, opts, GetGLPlatform(),
driver);
}
static DriverRegistration GLDriverRegistration(RDCDriver::OpenGL, &GL_CreateReplayDevice);
#endif
#if defined(RENDERDOC_SUPPORT_GLES) #if defined(RENDERDOC_SUPPORT_GLES)
ReplayStatus GLES_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, IReplayDriver **driver) ReplayStatus GLES_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, IReplayDriver **driver)
@@ -3587,3 +3586,36 @@ ReplayStatus GLES_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, IR
static DriverRegistration GLESDriverRegistration(RDCDriver::OpenGLES, &GLES_CreateReplayDevice); static DriverRegistration GLESDriverRegistration(RDCDriver::OpenGLES, &GLES_CreateReplayDevice);
#endif #endif
#if defined(RENDERDOC_SUPPORT_GL)
ReplayStatus GL_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, IReplayDriver **driver)
{
if(RenderDoc::Inst().GetGlobalEnvironment().waylandDisplay)
{
#if defined(RENDERDOC_SUPPORT_GLES)
RDCLOG("Forcing EGL device creation for wayland");
return GLES_CreateReplayDevice(rdc, opts, driver);
#else
RDCERR("GLES support must be enabled at build time when using Wayland");
return ReplayStatus::InternalError;
#endif
}
RDCDEBUG("Creating an OpenGL replay device");
bool load_ok = GetGLPlatform().PopulateForReplay();
if(!load_ok)
{
RDCERR("Couldn't find required platform GL function addresses");
return ReplayStatus::APIInitFailed;
}
return CreateReplayDevice(rdc ? rdc->GetDriver() : RDCDriver::OpenGL, rdc, opts, GetGLPlatform(),
driver);
}
static DriverRegistration GLDriverRegistration(RDCDriver::OpenGL, &GL_CreateReplayDevice);
#endif
+1
View File
@@ -234,6 +234,7 @@ public:
void SetReplayData(GLWindowingData data); void SetReplayData(GLWindowingData data);
bool IsReplayContext(void *ctx) { return m_ReplayCtx.ctx == NULL || ctx == m_ReplayCtx.ctx; } bool IsReplayContext(void *ctx) { return m_ReplayCtx.ctx == NULL || ctx == m_ReplayCtx.ctx; }
bool HasDebugContext() { return m_DebugCtx != NULL; }
private: private:
void OpenGLFillCBufferVariables(GLuint prog, bool bufferBacked, std::string prefix, void OpenGLFillCBufferVariables(GLuint prog, bool bufferBacked, std::string prefix,
const rdcarray<ShaderConstant> &variables, const rdcarray<ShaderConstant> &variables,
+8 -8
View File
@@ -29,7 +29,7 @@
namespace Keyboard namespace Keyboard
{ {
void CloneDisplay(Display *dpy); void UseXlibDisplay(Display *dpy);
} }
class GLXHook : LibraryHook class GLXHook : LibraryHook
@@ -65,18 +65,18 @@ public:
// callback and we'll get a specific library handle. // callback and we'll get a specific library handle.
static void EnsureRealLibraryLoaded() static void EnsureRealLibraryLoaded()
{ {
if(RenderDoc::Inst().IsReplayApp())
return;
if(glxhook.handle == RTLD_NEXT) if(glxhook.handle == RTLD_NEXT)
{ {
RDCLOG("Loading libGL at the last second"); if(!RenderDoc::Inst().IsReplayApp())
RDCLOG("Loading libGL at the last second");
void *handle = Process::LoadModule("libGL.so.1"); void *handle = Process::LoadModule("libGL.so.1");
if(!handle) if(!handle)
handle = Process::LoadModule("libGL.so"); handle = Process::LoadModule("libGL.so");
if(!handle) if(!handle)
handle = Process::LoadModule("libGLX.so.0"); handle = Process::LoadModule("libGLX.so.0");
glxhook.handle = handle;
} }
} }
@@ -106,7 +106,7 @@ HOOK_EXPORT GLXContext glXCreateContext_renderdoc_hooked(Display *dpy, XVisualIn
int value = 0; int value = 0;
Keyboard::CloneDisplay(dpy); Keyboard::UseXlibDisplay(dpy);
GLX.glXGetConfig(dpy, vis, GLX_BUFFER_SIZE, &value); GLX.glXGetConfig(dpy, vis, GLX_BUFFER_SIZE, &value);
init.colorBits = value; init.colorBits = value;
@@ -251,7 +251,7 @@ HOOK_EXPORT GLXContext glXCreateContextAttribsARB_renderdoc_hooked(Display *dpy,
int value = 0; int value = 0;
Keyboard::CloneDisplay(dpy); Keyboard::UseXlibDisplay(dpy);
GLX.glXGetConfig(dpy, vis, GLX_BUFFER_SIZE, &value); GLX.glXGetConfig(dpy, vis, GLX_BUFFER_SIZE, &value);
init.colorBits = value; init.colorBits = value;
@@ -444,7 +444,7 @@ HOOK_EXPORT void glXSwapBuffers_renderdoc_hooked(Display *dpy, GLXDrawable drawa
glxhook.UpdateWindowSize(data, dpy, drawable); glxhook.UpdateWindowSize(data, dpy, drawable);
} }
glxhook.driver.SwapBuffers((void *)drawable); glxhook.driver.SwapBuffers(WindowingSystem::Xlib, (void *)drawable);
GLX.glXSwapBuffers(dpy, drawable); GLX.glXSwapBuffers(dpy, drawable);
} }
+1 -1
View File
@@ -181,7 +181,7 @@ void WGLHook::ProcessSwapBuffers(HDC dc)
{ {
SCOPED_LOCK(glLock); SCOPED_LOCK(glLock);
driver.SwapBuffers(w); driver.SwapBuffers(WindowingSystem::Win32, w);
} }
SetLastError(0); SetLastError(0);
@@ -293,7 +293,7 @@ void WrappedOpenGL::HandleVRFrameMarkers(const GLchar *buf, GLsizei length)
{ {
if(strstr(buf, "vr-marker,frame_end,type,application") != NULL) if(strstr(buf, "vr-marker,frame_end,type,application") != NULL)
{ {
SwapBuffers((void *)m_ActiveContexts[Threading::GetCurrentID()].wnd); SwapBuffers(WindowingSystem::Headless, (void *)m_ActiveContexts[Threading::GetCurrentID()].wnd);
m_UsesVRMarkers = true; m_UsesVRMarkers = true;
if(IsActiveCapturing(m_State)) if(IsActiveCapturing(m_State))
@@ -401,7 +401,7 @@ void WrappedOpenGL::glInsertEventMarkerEXT(GLsizei length, const GLchar *marker)
void WrappedOpenGL::glFrameTerminatorGREMEDY() void WrappedOpenGL::glFrameTerminatorGREMEDY()
{ {
SwapBuffers((void *)m_ActiveContexts[Threading::GetCurrentID()].wnd); SwapBuffers(WindowingSystem::Headless, (void *)m_ActiveContexts[Threading::GetCurrentID()].wnd);
} }
void WrappedOpenGL::glStringMarkerGREMEDY(GLsizei len, const void *string) void WrappedOpenGL::glStringMarkerGREMEDY(GLsizei len, const void *string)
+4
View File
@@ -111,6 +111,10 @@ elseif(UNIX)
add_definitions(-DVK_USE_PLATFORM_XCB_KHR) add_definitions(-DVK_USE_PLATFORM_XCB_KHR)
endif() endif()
if(ENABLE_WAYLAND)
add_definitions(-DVK_USE_PLATFORM_WAYLAND_KHR)
endif()
set(VULKAN_LAYER_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/${LIB_SUBFOLDER_TRAIL_SLASH}librenderdoc.so") set(VULKAN_LAYER_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/${LIB_SUBFOLDER_TRAIL_SLASH}librenderdoc.so")
set(json_in ${CMAKE_CURRENT_SOURCE_DIR}/renderdoc.json) set(json_in ${CMAKE_CURRENT_SOURCE_DIR}/renderdoc.json)
+2 -3
View File
@@ -43,9 +43,8 @@ VkResult WrappedVulkan::vkCreateAndroidSurfaceKHR(VkInstance instance,
WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface); WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface);
// since there's no point in allocating a full resource record and storing the window wrapped->record =
// handle under there somewhere, we just cast. We won't use the resource record for anything PackWindowHandleInRecord(WindowingSystem::Android, (void *)(uintptr_t)pCreateInfo->window);
wrapped->record = (VkResourceRecord *)(uintptr_t)pCreateInfo->window;
} }
return ret; return ret;
+4 -6
View File
@@ -51,9 +51,8 @@ VkResult WrappedVulkan::vkCreateMacOSSurfaceMVK(VkInstance instance,
WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface); WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface);
// since there's no point in allocating a full resource record and storing the window wrapped->record =
// handle under there somewhere, we just cast. We won't use the resource record for anything PackWindowHandleInRecord(WindowingSystem::MacOS, (void *)(uintptr_t)pCreateInfo->pView);
wrapped->record = (VkResourceRecord *)(uintptr_t)pCreateInfo->pView;
} }
return ret; return ret;
@@ -80,9 +79,8 @@ VkResult WrappedVulkan::vkCreateMetalSurfaceEXT(VkInstance instance,
WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface); WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface);
// since there's no point in allocating a full resource record and storing the window wrapped->record =
// handle under there somewhere, we just cast. We won't use the resource record for anything PackWindowHandleInRecord(WindowingSystem::MacOS, (void *)(uintptr_t)pCreateInfo->pLayer);
wrapped->record = (VkResourceRecord *)(uintptr_t)pCreateInfo->pLayer;
} }
return ret; return ret;
+14
View File
@@ -101,6 +101,20 @@ int SampleCount(VkSampleCountFlagBits countFlag);
int SampleIndex(VkSampleCountFlagBits countFlag); int SampleIndex(VkSampleCountFlagBits countFlag);
int StageIndex(VkShaderStageFlagBits stageFlag); int StageIndex(VkShaderStageFlagBits stageFlag);
struct PackedWindowHandle
{
PackedWindowHandle(WindowingSystem s, void *h) : system(s), handle(h) {}
WindowingSystem system;
void *handle;
};
struct VkResourceRecord;
inline VkResourceRecord *PackWindowHandleInRecord(WindowingSystem system, void *handle)
{
return (VkResourceRecord *)new PackedWindowHandle(system, handle);
}
class WrappedVulkan; class WrappedVulkan;
struct VkPackedVersion struct VkPackedVersion
+5
View File
@@ -1010,6 +1010,11 @@ static const VkExtensionProperties supportedExtensions[] = {
{ {
VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME, VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION, VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME, VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION,
}, },
#ifdef VK_KHR_wayland_surface
{
VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_SPEC_VERSION,
},
#endif
#ifdef VK_KHR_win32_keyed_mutex #ifdef VK_KHR_win32_keyed_mutex
{ {
VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME, VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION, VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME, VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION,
+11
View File
@@ -1697,6 +1697,17 @@ public:
VkSurfaceKHR *pSurface); VkSurfaceKHR *pSurface);
#endif #endif
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
// VK_KHR_wayland_surface
VkResult vkCreateWaylandSurfaceKHR(VkInstance instance,
const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface);
VkBool32 vkGetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
struct wl_display *display);
#endif
// VK_KHR_display and VK_KHR_display_swapchain. These have no library or include dependencies so // VK_KHR_display and VK_KHR_display_swapchain. These have no library or include dependencies so
// wecan just compile them in on all platforms to reduce platform-specific code. They are mostly // wecan just compile them in on all platforms to reduce platform-specific code. They are mostly
// only actually used though on *nix. // only actually used though on *nix.
+2 -1
View File
@@ -43,7 +43,8 @@ VkResult WrappedVulkan::vkCreateStreamDescriptorSurfaceGGP(
WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface); WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface);
wrapped->record = (VkResourceRecord *)(uintptr_t)pCreateInfo->streamDescriptor; wrapped->record = PackWindowHandleInRecord(WindowingSystem::GGP,
(void *)(uintptr_t)pCreateInfo->streamDescriptor);
} }
return ret; return ret;
} }
+30 -5
View File
@@ -174,6 +174,26 @@
#endif #endif
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
#define HookInitInstance_PlatformSpecific_Wayland() \
HookInitExtension(VK_KHR_wayland_surface, CreateWaylandSurfaceKHR); \
HookInitExtension(VK_KHR_wayland_surface, GetPhysicalDeviceWaylandPresentationSupportKHR);
#define HookDefine_PlatformSpecific_Wayland() \
HookDefine4(VkResult, vkCreateWaylandSurfaceKHR, VkInstance, instance, \
const VkWaylandSurfaceCreateInfoKHR *, pCreateInfo, const VkAllocationCallbacks *, \
pAllocator, VkSurfaceKHR *, pSurface); \
HookDefine3(VkBool32, vkGetPhysicalDeviceWaylandPresentationSupportKHR, VkPhysicalDevice, \
physicalDevice, uint32_t, queueFamilyIndex, struct wl_display *, display);
#else
#define HookInitInstance_PlatformSpecific_Wayland()
#define HookDefine_PlatformSpecific_Wayland()
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR) #if defined(VK_USE_PLATFORM_XLIB_KHR)
#define HookInitInstance_PlatformSpecific_Xlib() \ #define HookInitInstance_PlatformSpecific_Xlib() \
@@ -200,11 +220,14 @@
#endif #endif
#define HookInitInstance_PlatformSpecific() \ #define HookInitInstance_PlatformSpecific() \
HookInitInstance_PlatformSpecific_Xcb() HookInitInstance_PlatformSpecific_Xlib() HookInitInstance_PlatformSpecific_Xcb() HookInitInstance_PlatformSpecific_Xlib() \
HookInitInstance_PlatformSpecific_Wayland()
#define HookInitDevice_PlatformSpecific() #define HookInitDevice_PlatformSpecific()
#define HookDefine_PlatformSpecific() \
HookDefine_PlatformSpecific_Xcb() HookDefine_PlatformSpecific_Xlib() #define HookDefine_PlatformSpecific() \
HookDefine_PlatformSpecific_Xcb() HookDefine_PlatformSpecific_Xlib() \
HookDefine_PlatformSpecific_Wayland()
#endif #endif
@@ -375,6 +398,7 @@
DeclExt(KHR_get_display_properties2); \ DeclExt(KHR_get_display_properties2); \
DeclExt(EXT_headless_surface); \ DeclExt(EXT_headless_surface); \
DeclExt(EXT_metal_surface); \ DeclExt(EXT_metal_surface); \
DeclExt(KHR_wayland_surface); \
/* device extensions */ \ /* device extensions */ \
DeclExt(EXT_debug_marker); \ DeclExt(EXT_debug_marker); \
DeclExt(GGP_frame_token); \ DeclExt(GGP_frame_token); \
@@ -457,7 +481,8 @@
CheckExt(EXT_calibrated_timestamps, VKXX); \ CheckExt(EXT_calibrated_timestamps, VKXX); \
CheckExt(EXT_full_screen_exclusive, VKXX); \ CheckExt(EXT_full_screen_exclusive, VKXX); \
CheckExt(EXT_headless_surface, VKXX); \ CheckExt(EXT_headless_surface, VKXX); \
CheckExt(EXT_metal_surface, VKXX); CheckExt(EXT_metal_surface, VKXX); \
CheckExt(KHR_wayland_surface, VKXX);
#define CheckDeviceExts() \ #define CheckDeviceExts() \
CheckExt(EXT_debug_marker, VKXX); \ CheckExt(EXT_debug_marker, VKXX); \
+95 -10
View File
@@ -41,7 +41,7 @@ VkBool32 WrappedVulkan::vkGetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalD
namespace Keyboard namespace Keyboard
{ {
void UseConnection(xcb_connection_t *conn); void UseXcbConnection(xcb_connection_t *conn);
} }
VkResult WrappedVulkan::vkCreateXcbSurfaceKHR(VkInstance instance, VkResult WrappedVulkan::vkCreateXcbSurfaceKHR(VkInstance instance,
@@ -61,11 +61,57 @@ VkResult WrappedVulkan::vkCreateXcbSurfaceKHR(VkInstance instance,
WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface); WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface);
// since there's no point in allocating a full resource record and storing the window wrapped->record =
// handle under there somewhere, we just cast. We won't use the resource record for anything PackWindowHandleInRecord(WindowingSystem::XCB, (void *)(uintptr_t)pCreateInfo->window);
wrapped->record = (VkResourceRecord *)(uintptr_t)pCreateInfo->window;
Keyboard::UseConnection(pCreateInfo->connection); Keyboard::UseXcbConnection(pCreateInfo->connection);
Keyboard::AddInputWindow(WindowingSystem::Xlib, (void *)(uintptr_t)pCreateInfo->window);
}
return ret;
}
#endif
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
namespace Keyboard
{
void UseWaylandDisplay(wl_display *disp);
}
VkBool32 WrappedVulkan::vkGetPhysicalDeviceWaylandPresentationSupportKHR(
VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display *display)
{
return ObjDisp(physicalDevice)
->GetPhysicalDeviceWaylandPresentationSupportKHR(Unwrap(physicalDevice), queueFamilyIndex,
display);
}
VkResult WrappedVulkan::vkCreateWaylandSurfaceKHR(VkInstance instance,
const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkSurfaceKHR *pSurface)
{
// should not come in here at all on replay
RDCASSERT(IsCaptureMode(m_State));
VkResult ret = ObjDisp(instance)->CreateWaylandSurfaceKHR(Unwrap(instance), pCreateInfo,
pAllocator, pSurface);
if(ret == VK_SUCCESS)
{
GetResourceManager()->WrapResource(Unwrap(instance), *pSurface);
WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface);
wrapped->record =
PackWindowHandleInRecord(WindowingSystem::Wayland, (void *)(uintptr_t)pCreateInfo->surface);
Keyboard::UseWaylandDisplay(pCreateInfo->display);
Keyboard::AddInputWindow(WindowingSystem::Wayland, pCreateInfo->surface);
} }
return ret; return ret;
@@ -85,7 +131,7 @@ VkBool32 WrappedVulkan::vkGetPhysicalDeviceXlibPresentationSupportKHR(
namespace Keyboard namespace Keyboard
{ {
void CloneDisplay(Display *dpy); void UseXlibDisplay(Display *dpy);
} }
VkResult WrappedVulkan::vkCreateXlibSurfaceKHR(VkInstance instance, VkResult WrappedVulkan::vkCreateXlibSurfaceKHR(VkInstance instance,
@@ -105,11 +151,12 @@ VkResult WrappedVulkan::vkCreateXlibSurfaceKHR(VkInstance instance,
WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface); WrappedVkSurfaceKHR *wrapped = GetWrapped(*pSurface);
// since there's no point in allocating a full resource record and storing the window wrapped->record =
// handle under there somewhere, we just cast. We won't use the resource record for anything PackWindowHandleInRecord(WindowingSystem::Xlib, (void *)(uintptr_t)pCreateInfo->window);
wrapped->record = (VkResourceRecord *)pCreateInfo->window;
Keyboard::CloneDisplay(pCreateInfo->dpy); Keyboard::UseXlibDisplay(pCreateInfo->dpy);
Keyboard::AddInputWindow(WindowingSystem::Xlib, (void *)(uintptr_t)pCreateInfo->window);
} }
return ret; return ret;
@@ -152,6 +199,15 @@ void VulkanReplay::OutputWindow::SetWindowHandle(WindowingData window)
} }
#endif #endif
#if ENABLED(RDOC_WAYLAND)
if(window.system == WindowingSystem::Wayland)
{
wayland.display = window.wayland.display;
wayland.window = window.wayland.window;
return;
}
#endif
RDCERR("Unrecognised/unsupported window system %d", window.system); RDCERR("Unrecognised/unsupported window system %d", window.system);
} }
@@ -193,6 +249,24 @@ void VulkanReplay::OutputWindow::CreateSurface(WrappedVulkan *driver, VkInstance
} }
#endif #endif
#if ENABLED(RDOC_WAYLAND)
if(m_WindowSystem == WindowingSystem::Wayland)
{
VkWaylandSurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = NULL;
createInfo.flags = 0;
createInfo.display = wayland.display;
createInfo.surface = wayland.window;
VkResult vkr = ObjDisp(inst)->CreateWaylandSurfaceKHR(Unwrap(inst), &createInfo, NULL, &surface);
RDCASSERTEQUAL(vkr, VK_SUCCESS);
return;
}
#endif
RDCERR("Unrecognised/unsupported window system %d", m_WindowSystem); RDCERR("Unrecognised/unsupported window system %d", m_WindowSystem);
} }
@@ -239,6 +313,17 @@ void VulkanReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h
} }
#endif #endif
#if ENABLED(RDOC_WAYLAND)
if(outw.m_WindowSystem == WindowingSystem::Wayland)
{
RDCWARN("Need Wayland query for current surface dimensions");
w = RDCMAX(1U, outw.width);
h = RDCMAX(1U, outw.height);
return;
}
#endif
RDCERR("Unrecognised/unsupported window system %d", outw.m_WindowSystem); RDCERR("Unrecognised/unsupported window system %d", outw.m_WindowSystem);
} }
+24 -3
View File
@@ -52,9 +52,10 @@ void WrappedVulkan::AddRequiredExtensions(bool instance, std::vector<std::string
// check if our compile-time options expect any WSI to be available, or if it's all disabled // check if our compile-time options expect any WSI to be available, or if it's all disabled
#define EXPECT_WSI 0 #define EXPECT_WSI 0
#if(defined(VK_USE_PLATFORM_ANDROID_KHR) || defined(VK_USE_PLATFORM_XCB_KHR) || \ #if(defined(VK_USE_PLATFORM_ANDROID_KHR) || defined(VK_USE_PLATFORM_XCB_KHR) || \
defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_MACOS_MVK) || \ defined(VK_USE_PLATFORM_WAYLAND_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || \
defined(VK_USE_PLATFORM_METAL_EXT) || defined(VK_USE_PLATFORM_GGP)) defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT) || \
defined(VK_USE_PLATFORM_GGP))
#undef EXPECT_WSI #undef EXPECT_WSI
#define EXPECT_WSI 1 #define EXPECT_WSI 1
@@ -68,6 +69,21 @@ void WrappedVulkan::AddRequiredExtensions(bool instance, std::vector<std::string
extensionList.end()) extensionList.end())
extensionList.push_back(VK_KHR_SURFACE_EXTENSION_NAME); extensionList.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
// check if supported
if(supportedExtensions.find(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME) != supportedExtensions.end())
{
m_SupportedWindowSystems.push_back(WindowingSystem::Wayland);
// don't add duplicates
if(std::find(extensionList.begin(), extensionList.end(),
VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME) == extensionList.end())
{
extensionList.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
}
}
#endif
#if defined(VK_USE_PLATFORM_XCB_KHR) #if defined(VK_USE_PLATFORM_XCB_KHR)
// check if supported // check if supported
if(supportedExtensions.find(VK_KHR_XCB_SURFACE_EXTENSION_NAME) != supportedExtensions.end()) if(supportedExtensions.find(VK_KHR_XCB_SURFACE_EXTENSION_NAME) != supportedExtensions.end())
@@ -198,6 +214,11 @@ void WrappedVulkan::AddRequiredExtensions(bool instance, std::vector<std::string
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
#endif #endif
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
RDCWARN("Wayland Output requires the '%s' extension to be present",
VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
#endif
#if defined(VK_USE_PLATFORM_XCB_KHR) #if defined(VK_USE_PLATFORM_XCB_KHR)
RDCWARN("XCB Output requires the '%s' extension to be present", RDCWARN("XCB Output requires the '%s' extension to be present",
VK_KHR_XCB_SURFACE_EXTENSION_NAME); VK_KHR_XCB_SURFACE_EXTENSION_NAME);
+22 -2
View File
@@ -79,13 +79,33 @@
#endif #endif
#if ENABLED(RDOC_WAYLAND)
#define WINDOW_HANDLE_WAYLAND \
struct \
{ \
wl_display *display; \
wl_surface *window; \
} wayland;
#else
#define WINDOW_HANDLE_WAYLAND \
struct \
{ \
} wayland;
#endif
#define WINDOW_HANDLE_DECL \ #define WINDOW_HANDLE_DECL \
WINDOW_HANDLE_XLIB \ WINDOW_HANDLE_XLIB \
WINDOW_HANDLE_XCB WINDOW_HANDLE_XCB \
WINDOW_HANDLE_WAYLAND
#define WINDOW_HANDLE_INIT \ #define WINDOW_HANDLE_INIT \
RDCEraseEl(xlib); \ RDCEraseEl(xlib); \
RDCEraseEl(xcb); RDCEraseEl(xcb); \
RDCEraseEl(wayland);
#elif ENABLED(RDOC_APPLE) || ENABLED(RDOC_GGP) #elif ENABLED(RDOC_APPLE) || ENABLED(RDOC_GGP)
+2 -2
View File
@@ -154,9 +154,9 @@ VkResult WrappedVulkan::vkCreateWin32SurfaceKHR(VkInstance instance,
// since there's no point in allocating a full resource record and storing the window // since there's no point in allocating a full resource record and storing the window
// handle under there somewhere, we just cast. We won't use the resource record for anything // handle under there somewhere, we just cast. We won't use the resource record for anything
wrapped->record = (VkResourceRecord *)pCreateInfo->hwnd; wrapped->record = PackWindowHandleInRecord(WindowingSystem::Win32, (void *)pCreateInfo->hwnd);
Keyboard::AddInputWindow((void *)pCreateInfo->hwnd); Keyboard::AddInputWindow(WindowingSystem::Win32, (void *)pCreateInfo->hwnd);
} }
return ret; return ret;
@@ -491,7 +491,7 @@ void WrappedVulkan::WrapAndProcessCreatedSwapchain(VkDevice device,
SwapchainInfo &swapInfo = *record->swapInfo; SwapchainInfo &swapInfo = *record->swapInfo;
// sneaky casting of window handle into record // sneaky casting of window handle into record
swapInfo.wndHandle = (RENDERDOC_WindowHandle)GetRecord(pCreateInfo->surface); swapInfo.wndHandle = ((PackedWindowHandle *)GetRecord(pCreateInfo->surface))->handle;
{ {
SCOPED_LOCK(m_SwapLookupLock); SCOPED_LOCK(m_SwapLookupLock);
@@ -846,7 +846,11 @@ void WrappedVulkan::vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surfac
// record pointer has window handle packed in // record pointer has window handle packed in
if(wrapper->record) if(wrapper->record)
Keyboard::RemoveInputWindow((void *)wrapper->record); {
PackedWindowHandle *wnd = (PackedWindowHandle *)wrapper->record;
Keyboard::RemoveInputWindow(wnd->system, wnd->handle);
delete wnd;
}
// now set record pointer back to NULL so no-one tries to delete it // now set record pointer back to NULL so no-one tries to delete it
wrapper->record = NULL; wrapper->record = NULL;
+2 -2
View File
@@ -356,8 +356,8 @@ inline bool slurp(const char *filename, std::vector<unsigned char> &buffer)
namespace Keyboard namespace Keyboard
{ {
void Init(); void Init();
void AddInputWindow(void *wnd); void AddInputWindow(WindowingSystem windowSystem, void *wnd);
void RemoveInputWindow(void *wnd); void RemoveInputWindow(WindowingSystem windowSystem, void *wnd);
bool GetKeyState(int key); bool GetKeyState(int key);
bool PlatformHasKeyInput(); bool PlatformHasKeyInput();
}; };
@@ -40,11 +40,11 @@ bool PlatformHasKeyInput()
return false; return false;
} }
void AddInputWindow(void *wnd) void AddInputWindow(WindowingSystem windowSystem, void *wnd)
{ {
} }
void RemoveInputWindow(void *wnd) void RemoveInputWindow(WindowingSystem windowSystem, void *wnd)
{ {
} }
+2 -2
View File
@@ -45,11 +45,11 @@ bool PlatformHasKeyInput()
return false; return false;
} }
void AddInputWindow(void *wnd) void AddInputWindow(WindowingSystem windowSystem, void *wnd)
{ {
} }
void RemoveInputWindow(void *wnd) void RemoveInputWindow(WindowingSystem windowSystem, void *wnd)
{ {
} }
+2 -2
View File
@@ -50,11 +50,11 @@ bool PlatformHasKeyInput()
return false; return false;
} }
void AddInputWindow(void *wnd) void AddInputWindow(WindowingSystem windowSystem, void *wnd)
{ {
} }
void RemoveInputWindow(void *wnd) void RemoveInputWindow(WindowingSystem windowSystem, void *wnd)
{ {
} }
+298 -8
View File
@@ -32,6 +32,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <set>
#include "api/app/renderdoc_app.h" #include "api/app/renderdoc_app.h"
#include "common/threading.h" #include "common/threading.h"
#include "os/os_specific.h" #include "os/os_specific.h"
@@ -47,6 +48,11 @@
#include <xcb/xcb_keysyms.h> #include <xcb/xcb_keysyms.h>
#endif #endif
#if ENABLED(RDOC_WAYLAND)
#include <linux/input.h>
#include <wayland-client.h>
#endif
namespace Keyboard namespace Keyboard
{ {
void Init() void Init()
@@ -55,7 +61,7 @@ void Init()
bool PlatformHasKeyInput() bool PlatformHasKeyInput()
{ {
#if ENABLED(RDOC_XCB) || ENABLED(RDOC_XLIB) #if ENABLED(RDOC_XCB) || ENABLED(RDOC_XLIB) || ENABLED(RDOC_WAYLAND)
return true; return true;
#else #else
return false; return false;
@@ -66,7 +72,7 @@ bool PlatformHasKeyInput()
Display *CurrentXDisplay = NULL; Display *CurrentXDisplay = NULL;
void CloneDisplay(Display *dpy) void UseXlibDisplay(Display *dpy)
{ {
if(CurrentXDisplay || dpy == NULL) if(CurrentXDisplay || dpy == NULL)
return; return;
@@ -137,7 +143,7 @@ bool GetXlibKeyState(int key)
// if RENDERDOC_WINDOWING_XLIB is not enabled // if RENDERDOC_WINDOWING_XLIB is not enabled
void CloneDisplay(Display *dpy) void UseXlibDisplay(Display *dpy)
{ {
} }
@@ -153,7 +159,7 @@ bool GetXlibKeyState(int key)
xcb_connection_t *connection; xcb_connection_t *connection;
xcb_key_symbols_t *symbols; xcb_key_symbols_t *symbols;
void UseConnection(xcb_connection_t *conn) void UseXcbConnection(xcb_connection_t *conn)
{ {
connection = conn; connection = conn;
symbols = xcb_key_symbols_alloc(conn); symbols = xcb_key_symbols_alloc(conn);
@@ -233,6 +239,10 @@ bool GetXCBKeyState(int key)
// if RENDERDOC_WINDOWING_XCB is not enabled // if RENDERDOC_WINDOWING_XCB is not enabled
void UseXcbConnection(xcb_connection_t *conn)
{
}
bool GetXCBKeyState(int key) bool GetXCBKeyState(int key)
{ {
return false; return false;
@@ -240,18 +250,298 @@ bool GetXCBKeyState(int key)
#endif #endif
void AddInputWindow(void *wnd) #if ENABLED(RDOC_WAYLAND)
#include <wayland-client.h>
std::set<wl_display *> displays;
std::set<wl_surface *> surfaces;
std::map<rdcpair<wl_registry *, uint32_t>, wl_seat *> seatNames;
std::map<wl_seat *, wl_keyboard *> seatKeyboard;
bool inFocus = false;
Threading::CriticalSection waylandLock;
bool keyState[eRENDERDOC_Key_Max] = {};
void WaylandKeymapDummy(void *data, wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size)
{ {
// TODO check against this drawable & parent window being focused in GetKeyState
} }
void RemoveInputWindow(void *wnd) void WaylandModifiersDummy(void *data, wl_keyboard *keyboard, uint32_t serial,
uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked,
uint32_t group)
{ {
} }
void WaylandRepeatInfoDummy(void *data, wl_keyboard *keyboard, int32_t rate, int32_t delay)
{
}
void WaylandEnter(void *data, wl_keyboard *keyboard, uint32_t serial, wl_surface *surf, wl_array *keys)
{
SCOPED_LOCK(waylandLock);
inFocus = surfaces.find(surf) != surfaces.end();
RDCEraseEl(keyState);
}
void WaylandLeave(void *data, wl_keyboard *keyboard, uint32_t serial, wl_surface *surf)
{
SCOPED_LOCK(waylandLock);
inFocus = false;
RDCEraseEl(keyState);
}
void WaylandKeypress(void *data, wl_keyboard *keyboard, uint32_t serial, uint32_t time,
uint32_t key, uint32_t state)
{
int keyIdx = -1;
switch(key)
{
case KEY_0: keyIdx = eRENDERDOC_Key_0; break;
case KEY_1: keyIdx = eRENDERDOC_Key_1; break;
case KEY_2: keyIdx = eRENDERDOC_Key_2; break;
case KEY_3: keyIdx = eRENDERDOC_Key_3; break;
case KEY_4: keyIdx = eRENDERDOC_Key_4; break;
case KEY_5: keyIdx = eRENDERDOC_Key_5; break;
case KEY_6: keyIdx = eRENDERDOC_Key_6; break;
case KEY_7: keyIdx = eRENDERDOC_Key_7; break;
case KEY_8: keyIdx = eRENDERDOC_Key_8; break;
case KEY_9: keyIdx = eRENDERDOC_Key_9; break;
case KEY_A: keyIdx = eRENDERDOC_Key_A; break;
case KEY_B: keyIdx = eRENDERDOC_Key_B; break;
case KEY_C: keyIdx = eRENDERDOC_Key_C; break;
case KEY_D: keyIdx = eRENDERDOC_Key_D; break;
case KEY_E: keyIdx = eRENDERDOC_Key_E; break;
case KEY_F: keyIdx = eRENDERDOC_Key_F; break;
case KEY_G: keyIdx = eRENDERDOC_Key_G; break;
case KEY_H: keyIdx = eRENDERDOC_Key_H; break;
case KEY_I: keyIdx = eRENDERDOC_Key_I; break;
case KEY_J: keyIdx = eRENDERDOC_Key_J; break;
case KEY_K: keyIdx = eRENDERDOC_Key_K; break;
case KEY_L: keyIdx = eRENDERDOC_Key_L; break;
case KEY_M: keyIdx = eRENDERDOC_Key_M; break;
case KEY_N: keyIdx = eRENDERDOC_Key_N; break;
case KEY_O: keyIdx = eRENDERDOC_Key_O; break;
case KEY_P: keyIdx = eRENDERDOC_Key_P; break;
case KEY_Q: keyIdx = eRENDERDOC_Key_Q; break;
case KEY_R: keyIdx = eRENDERDOC_Key_R; break;
case KEY_S: keyIdx = eRENDERDOC_Key_S; break;
case KEY_T: keyIdx = eRENDERDOC_Key_T; break;
case KEY_U: keyIdx = eRENDERDOC_Key_U; break;
case KEY_V: keyIdx = eRENDERDOC_Key_V; break;
case KEY_W: keyIdx = eRENDERDOC_Key_W; break;
case KEY_X: keyIdx = eRENDERDOC_Key_X; break;
case KEY_Y: keyIdx = eRENDERDOC_Key_Y; break;
case KEY_Z: keyIdx = eRENDERDOC_Key_Z; break;
case KEY_KPSLASH: keyIdx = eRENDERDOC_Key_Divide; break;
case KEY_KPASTERISK: keyIdx = eRENDERDOC_Key_Multiply; break;
case KEY_KPMINUS: keyIdx = eRENDERDOC_Key_Subtract; break;
case KEY_KPPLUS: keyIdx = eRENDERDOC_Key_Plus; break;
case KEY_F1: keyIdx = eRENDERDOC_Key_F1; break;
case KEY_F2: keyIdx = eRENDERDOC_Key_F2; break;
case KEY_F3: keyIdx = eRENDERDOC_Key_F3; break;
case KEY_F4: keyIdx = eRENDERDOC_Key_F4; break;
case KEY_F5: keyIdx = eRENDERDOC_Key_F5; break;
case KEY_F6: keyIdx = eRENDERDOC_Key_F6; break;
case KEY_F7: keyIdx = eRENDERDOC_Key_F7; break;
case KEY_F8: keyIdx = eRENDERDOC_Key_F8; break;
case KEY_F9: keyIdx = eRENDERDOC_Key_F9; break;
case KEY_F10: keyIdx = eRENDERDOC_Key_F10; break;
case KEY_F11: keyIdx = eRENDERDOC_Key_F11; break;
case KEY_F12: keyIdx = eRENDERDOC_Key_F12; break;
case KEY_HOME: keyIdx = eRENDERDOC_Key_Home; break;
case KEY_END: keyIdx = eRENDERDOC_Key_End; break;
case KEY_INSERT: keyIdx = eRENDERDOC_Key_Insert; break;
case KEY_DELETE: keyIdx = eRENDERDOC_Key_Delete; break;
case KEY_PAGEUP: keyIdx = eRENDERDOC_Key_PageUp; break;
case KEY_PAGEDOWN: keyIdx = eRENDERDOC_Key_PageDn; break;
case KEY_BACKSPACE: keyIdx = eRENDERDOC_Key_Backspace; break;
case KEY_TAB: keyIdx = eRENDERDOC_Key_Tab; break;
case KEY_SYSRQ: keyIdx = eRENDERDOC_Key_PrtScrn; break;
case KEY_PAUSE: keyIdx = eRENDERDOC_Key_Pause; break;
}
if(keyIdx < 0)
return;
{
SCOPED_LOCK(waylandLock);
keyState[keyIdx] = (state == WL_KEYBOARD_KEY_STATE_PRESSED);
}
}
void WaylandSeatCaps(void *data, wl_seat *seat, uint32_t capabilities)
{
if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD)
{
{
SCOPED_LOCK(waylandLock);
if(seatKeyboard[seat])
return;
}
wl_keyboard *keyboard = wl_seat_get_keyboard(seat);
static const wl_keyboard_listener listener = {
WaylandKeymapDummy, WaylandEnter, WaylandLeave,
WaylandKeypress, WaylandModifiersDummy, WaylandRepeatInfoDummy,
};
wl_keyboard_add_listener(keyboard, &listener, NULL);
{
SCOPED_LOCK(waylandLock);
seatKeyboard[seat] = keyboard;
}
}
else
{
wl_keyboard *keyboard = NULL;
{
SCOPED_LOCK(waylandLock);
keyboard = seatKeyboard[seat];
if(!keyboard)
return;
seatKeyboard[seat] = NULL;
}
wl_keyboard_destroy(keyboard);
}
}
void WaylandRegistryAdd(void *data, wl_registry *reg, uint32_t name, const char *iface,
uint32_t version)
{
if(!strcmp(iface, "wl_seat"))
{
wl_seat *seat = (wl_seat *)wl_registry_bind(reg, name, &wl_seat_interface, 1);
static const wl_seat_listener listener = {&WaylandSeatCaps};
wl_seat_add_listener(seat, &listener, NULL);
{
SCOPED_LOCK(waylandLock);
seatNames[{reg, name}] = seat;
}
}
}
void WaylandRegistryRemove(void *data, wl_registry *reg, uint32_t name)
{
SCOPED_LOCK(waylandLock);
auto it = seatNames.find({reg, name});
if(it != seatNames.end())
{
wl_seat_destroy(it->second);
seatNames.erase(it);
}
}
void UseWaylandDisplay(wl_display *disp)
{
// only listen to each display once at most
{
SCOPED_LOCK(waylandLock);
if(displays.find(disp) != displays.end())
return;
displays.insert(disp);
}
static const wl_registry_listener listener = {&WaylandRegistryAdd, &WaylandRegistryRemove};
// get the registry and listen to it. This will then let us find seats
wl_registry_add_listener(wl_display_get_registry(disp), &listener, NULL);
}
void AddWaylandInputWindow(wl_surface *wnd)
{
SCOPED_LOCK(waylandLock);
surfaces.insert(wnd);
}
void RemoveWaylandInputWindow(wl_surface *wnd)
{
SCOPED_LOCK(waylandLock);
surfaces.erase(wnd);
}
bool GetWaylandKeyState(int key)
{
SCOPED_LOCK(waylandLock);
return keyState[key];
}
#else
void UseWaylandDisplay(wl_display *disp)
{
}
void AddWaylandInputWindow(wl_surface *wnd)
{
}
void RemoveWaylandInputWindow(wl_surface *wnd)
{
}
bool GetWaylandKeyState(int key)
{
return false;
}
#endif
WindowingSystem UseUnknownDisplay(void *disp)
{
// could be wayland or xlib, try to detect.
// both Display* and wl_display* are valid pointers, so dereference and read the first pointer
// sized bytes
void *firstPointer = NULL;
memcpy(&firstPointer, disp, sizeof(void *));
// in a Display* we don't know what this contains, but in a wl_display it should point to the
// wl_display_interface exported symbol. Check with dladdr
Dl_info info;
if(dladdr(firstPointer, &info) && !strcmp(info.dli_sname, "wl_display_interface"))
{
UseWaylandDisplay((wl_display *)disp);
return WindowingSystem::Wayland;
}
else
{
UseXlibDisplay((Display *)disp);
return WindowingSystem::Xlib;
}
}
void AddInputWindow(WindowingSystem windowSystem, void *wnd)
{
if(windowSystem == WindowingSystem::Wayland)
{
AddWaylandInputWindow((wl_surface *)wnd);
}
else
{
// TODO check against this drawable & parent window being focused in GetKeyState
}
}
void RemoveInputWindow(WindowingSystem windowSystem, void *wnd)
{
if(windowSystem == WindowingSystem::Wayland)
{
RemoveWaylandInputWindow((wl_surface *)wnd);
}
}
bool GetKeyState(int key) bool GetKeyState(int key)
{ {
return GetXCBKeyState(key) || GetXlibKeyState(key); return GetXCBKeyState(key) || GetXlibKeyState(key) || GetWaylandKeyState(key);
} }
} }
+4 -2
View File
@@ -79,13 +79,15 @@ bool PlatformHasKeyInput()
std::set<HWND> inputWindows; std::set<HWND> inputWindows;
void AddInputWindow(void *wnd) void AddInputWindow(WindowingSystem windowSystem, void *wnd)
{ {
RDCASSERTEQUAL(windowSystem, WindowingSystem::Win32);
inputWindows.insert((HWND)wnd); inputWindows.insert((HWND)wnd);
} }
void RemoveInputWindow(void *wnd) void RemoveInputWindow(WindowingSystem windowSystem, void *wnd)
{ {
RDCASSERTEQUAL(windowSystem, WindowingSystem::Win32);
inputWindows.erase((HWND)wnd); inputWindows.erase((HWND)wnd);
} }
+10 -1
View File
@@ -51,7 +51,16 @@ static uint64_t GetHandle(WindowingData window)
#endif #endif
} }
RDCERR("Unrecognised window system %d", system); if(window.system == WindowingSystem::Wayland)
{
#if ENABLED(RDOC_WAYLAND)
return (uint64_t)window.wayland.window;
#else
RDCERR("Wayland windowing system data passed in, but support is not compiled in");
#endif
}
RDCERR("Unrecognised window system %s", ToStr(window.system).c_str());
return 0; return 0;
+5
View File
@@ -537,6 +537,11 @@ int main(int argc, char *argv[])
count++; count++;
#endif #endif
#if defined(RENDERDOC_WINDOWING_WAYLAND)
support += "Wayland (CAPTURE ONLY), ";
count++;
#endif
#if defined(RENDERDOC_SUPPORT_VULKAN) #if defined(RENDERDOC_SUPPORT_VULKAN)
support += "Vulkan KHR_display, "; support += "Vulkan KHR_display, ";
count++; count++;