mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-10 03:50:36 +00:00
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:
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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.")
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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) \
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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); \
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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++;
|
||||||
|
|||||||
Reference in New Issue
Block a user