Add a preview window ability to remote servers. Always on for android

* On android in particular this shows some sense of what's happening on
  the device and gives user feedback that it's not completely dead.
This commit is contained in:
baldurk
2018-01-01 17:31:23 +00:00
parent 7a2305ae31
commit 96e39cb781
12 changed files with 499 additions and 51 deletions
+18 -1
View File
@@ -488,6 +488,7 @@ DECLARE_REFLECTION_STRUCT(ResourceId);
// here and document them immediately below. They can be linked to from anywhere by name.
typedef std::function<bool()> RENDERDOC_KillCallback;
typedef std::function<void(float)> RENDERDOC_ProgressCallback;
typedef std::function<WindowingData(bool, const rdcarray<WindowingSystem> &)> RENDERDOC_PreviewWindowCallback;
DOCUMENT(R"(A stateful output handle that contains the current configuration for one particular view
of the capture. This allows multiple outputs to run independently without interfering with each
@@ -515,6 +516,19 @@ The different types are enumerated in :class:`ReplayOutputType`.
:param float progress: The latest progress amount.
.. function:: PreviewWindowCallback()
Not an actual member function - the signature for any ``PreviewWindowCallback`` callbacks.
Called when a preview window could optionally be opened to display some information. It will be
called repeatedly with :paramref:`active` set to ``True`` to allow any platform-specific message
pumping.
:param bool active: ``True`` if a preview window is active/opened, ``False`` if it has closed.
:return: The windowing data for a preview window, or empty/default values if no window should be
created.
:rtype: WindowingData
.. data:: NoResult
No result was found in e.g. :meth:`PickVertex`.
@@ -1858,9 +1872,12 @@ This function will block until a remote connection tells the server to shut down
:param int port: The port to listen on, or the default port if 0.
:param KillCallback killReplay: A callback that returns a ``bool`` indicating if the server should
be shut down or not.
:param PreviewWindowCallback previewWindow: A callback that returns information for a preview window
when the server wants to display some preview of the ongoing replay.
)");
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_BecomeRemoteServer(
const char *listenhost, uint32_t port, RENDERDOC_KillCallback killReplay);
const char *listenhost, uint32_t port, RENDERDOC_KillCallback killReplay,
RENDERDOC_PreviewWindowCallback previewWindow);
//////////////////////////////////////////////////////////////////////////
// Injection/execution capture functions.
+2 -1
View File
@@ -387,7 +387,8 @@ public:
bool IsReplayApp() const { return m_Replay; }
const string &GetConfigSetting(string name) { return m_ConfigSettings[name]; }
void SetConfigSetting(string name, string value) { m_ConfigSettings[name] = value; }
void BecomeRemoteServer(const char *listenhost, uint16_t port, RENDERDOC_KillCallback killReplay);
void BecomeRemoteServer(const char *listenhost, uint16_t port, RENDERDOC_KillCallback killReplay,
RENDERDOC_PreviewWindowCallback previewWindow);
void SetCaptureOptions(const CaptureOptions &opts);
const CaptureOptions &GetCaptureOptions() const { return m_Options; }
+40 -18
View File
@@ -146,7 +146,8 @@ static void InactiveRemoteClientThread(ClientThread *threadData)
}
}
static void ActiveRemoteClientThread(ClientThread *threadData)
static void ActiveRemoteClientThread(ClientThread *threadData,
RENDERDOC_PreviewWindowCallback previewWindow)
{
Network::Socket *&client = threadData->socket;
@@ -197,7 +198,8 @@ static void ActiveRemoteClientThread(ClientThread *threadData)
}
std::vector<std::string> tempFiles;
IRemoteDriver *driver = NULL;
IRemoteDriver *remoteDriver = NULL;
IReplayDriver *replayDriver = NULL;
ReplayProxy *proxy = NULL;
RDCFile *rdc = NULL;
Callstack::StackResolver *resolver = NULL;
@@ -229,6 +231,9 @@ static void ActiveRemoteClientThread(ClientThread *threadData)
{
reader.EndChunk();
if(proxy)
proxy->RefreshPreviewWindow();
WRITE_DATA_SCOPE();
SCOPED_SERIALISE_CHUNK(eRemoteServer_Ping);
}
@@ -378,7 +383,7 @@ static void ActiveRemoteClientThread(ClientThread *threadData)
reader.EndChunk();
RDCASSERT(driver == NULL && proxy == NULL && rdc == NULL);
RDCASSERT(remoteDriver == NULL && proxy == NULL && rdc == NULL);
ReplayStatus status = ReplayStatus::InternalError;
rdc = new RDCFile();
@@ -420,22 +425,32 @@ static void ActiveRemoteClientThread(ClientThread *threadData)
}
});
status = RenderDoc::Inst().CreateRemoteDriver(rdc, &driver);
// if we have a replay driver, try to create it so we can display a local preview e.g.
if(RenderDoc::Inst().HasReplayDriver(rdc->GetDriver()))
{
status = RenderDoc::Inst().CreateReplayDriver(rdc, &replayDriver);
if(replayDriver)
remoteDriver = replayDriver;
}
else
{
status = RenderDoc::Inst().CreateRemoteDriver(rdc, &remoteDriver);
}
if(status != ReplayStatus::Succeeded || driver == NULL)
if(status != ReplayStatus::Succeeded || remoteDriver == NULL)
{
RDCERR("Failed to create remote driver for driver '%s'", rdc->GetDriverName().c_str());
}
else
{
status = driver->ReadLogInitialisation(rdc, false);
status = remoteDriver->ReadLogInitialisation(rdc, false);
if(status != ReplayStatus::Succeeded)
{
RDCERR("Failed to initialise remote driver.");
driver->Shutdown();
driver = NULL;
remoteDriver->Shutdown();
remoteDriver = NULL;
}
else
{
@@ -445,7 +460,7 @@ static void ActiveRemoteClientThread(ClientThread *threadData)
Threading::JoinThread(ticker);
Threading::CloseThread(ticker);
proxy = new ReplayProxy(reader, writer, driver);
proxy = new ReplayProxy(reader, writer, remoteDriver, replayDriver, previewWindow);
}
}
}
@@ -692,11 +707,13 @@ static void ActiveRemoteClientThread(ClientThread *threadData)
{
reader.EndChunk();
if(driver)
driver->Shutdown();
driver = NULL;
SAFE_DELETE(proxy);
if(remoteDriver)
remoteDriver->Shutdown();
remoteDriver = NULL;
replayDriver = NULL;
SAFE_DELETE(rdc);
SAFE_DELETE(resolver);
}
@@ -746,9 +763,12 @@ static void ActiveRemoteClientThread(ClientThread *threadData)
}
}
if(driver)
driver->Shutdown();
SAFE_DELETE(proxy);
if(remoteDriver)
remoteDriver->Shutdown();
remoteDriver = NULL;
replayDriver = NULL;
SAFE_DELETE(rdc);
SAFE_DELETE(resolver);
@@ -766,7 +786,8 @@ static void ActiveRemoteClientThread(ClientThread *threadData)
}
void RenderDoc::BecomeRemoteServer(const char *listenhost, uint16_t port,
RENDERDOC_KillCallback killReplay)
RENDERDOC_KillCallback killReplay,
RENDERDOC_PreviewWindowCallback previewWindow)
{
Network::Socket *sock = Network::CreateServerSocket(listenhost, port, 1);
@@ -934,8 +955,9 @@ void RenderDoc::BecomeRemoteServer(const char *listenhost, uint16_t port,
activeClientData->socket = client;
activeClientData->allowExecution = allowExecution;
activeClientData->thread = Threading::CreateThread(
[activeClientData]() { ActiveRemoteClientThread(activeClientData); });
activeClientData->thread = Threading::CreateThread([activeClientData, previewWindow]() {
ActiveRemoteClientThread(activeClientData, previewWindow);
});
RDCLOG("Making active connection");
}
+142
View File
@@ -68,6 +68,8 @@
ReplayProxy::~ReplayProxy()
{
ShutdownPreviewWindow();
if(m_Proxy)
m_Proxy->Shutdown();
m_Proxy = NULL;
@@ -1295,6 +1297,9 @@ void ReplayProxy::Proxied_ReplayLog(ParamSerialiser &paramser, ReturnSerialiser
if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored)
m_Remote->ReplayLog(endEventID, replayType);
if(m_RemoteServer)
m_PreviewEvent = endEventID;
if(retser.IsReading())
{
m_TextureProxyCache.clear();
@@ -1834,6 +1839,141 @@ void ReplayProxy::EnsureBufCached(ResourceId bufid)
}
}
const DrawcallDescription *ReplayProxy::FindDraw(const rdcarray<DrawcallDescription> &drawcallList,
uint32_t eventId)
{
for(const DrawcallDescription &d : drawcallList)
{
if(!d.children.empty())
{
const DrawcallDescription *draw = FindDraw(d.children, eventId);
if(draw != NULL)
return draw;
}
if(d.eventId == eventId)
return &d;
}
return NULL;
}
void ReplayProxy::InitPreviewWindow()
{
if(m_Replay && m_PreviewWindow)
{
WindowingData data = m_PreviewWindow(true, m_Replay->GetSupportedWindowSystems());
if(data.system != WindowingSystem::Unknown)
m_PreviewOutput = m_Replay->MakeOutputWindow(data, false);
m_FrameRecord = m_Replay->GetFrameRecord();
}
}
void ReplayProxy::ShutdownPreviewWindow()
{
if(m_Replay && m_PreviewOutput)
{
m_Replay->DestroyOutputWindow(m_PreviewOutput);
m_PreviewWindow(false, {});
}
}
void ReplayProxy::RefreshPreviewWindow()
{
if(m_Replay && m_PreviewOutput)
{
m_Replay->BindOutputWindow(m_PreviewOutput, false);
m_Replay->ClearOutputWindowColor(m_PreviewOutput, FloatVector(0.0f, 0.0f, 0.0f, 1.0f));
int32_t winWidth = 1;
int32_t winHeight = 1;
m_Replay->GetOutputWindowDimensions(m_PreviewOutput, winWidth, winHeight);
m_Replay->RenderCheckerboard();
const DrawcallDescription *curDraw = FindDraw(m_FrameRecord.drawcallList, m_PreviewEvent);
if(curDraw)
{
TextureDisplay cfg = {};
cfg.red = cfg.green = cfg.blue = true;
cfg.alpha = false;
for(ResourceId id : curDraw->outputs)
{
if(id != ResourceId())
{
cfg.resourceId = id;
break;
}
}
// if we didn't get a colour target, try the depth target
if(cfg.resourceId == ResourceId() && curDraw->depthOut != ResourceId())
{
cfg.resourceId = curDraw->depthOut;
// red only for depth textures
cfg.green = cfg.blue = false;
}
// if we didn't get any target, use the copy destination
if(cfg.resourceId == ResourceId())
cfg.resourceId = curDraw->copyDestination;
// if we did get a texture, get the live ID for it
if(cfg.resourceId != ResourceId())
cfg.resourceId = m_Replay->GetLiveID(cfg.resourceId);
if(cfg.resourceId != ResourceId())
{
TextureDescription texInfo = m_Replay->GetTexture(cfg.resourceId);
cfg.typeHint = CompType::Typeless;
cfg.rangeMin = 0.0f;
cfg.rangeMax = 1.0f;
cfg.flipY = false;
cfg.hdrMultiplier = -1.0f;
cfg.linearDisplayAsGamma = true;
cfg.customShaderId = ResourceId();
cfg.mip = 0;
cfg.sliceFace = 0;
cfg.sampleIdx = 0;
cfg.rawOutput = false;
cfg.backgroundColor = FloatVector(0, 0, 0, 0);
cfg.overlay = DebugOverlay::NoOverlay;
cfg.xOffset = 0.0f;
cfg.yOffset = 0.0f;
float xScale = float(winWidth) / float(texInfo.width);
float yScale = float(winHeight) / float(texInfo.height);
if(xScale > yScale)
{
// use the y scale, calculate the x offset to centre horizontally
cfg.scale = yScale;
cfg.xOffset = (float(winWidth) - float(texInfo.width) * cfg.scale) / 2.0f;
}
else
{
// use the x scale, calculate the y offset to centre vertically
cfg.scale = xScale;
cfg.yOffset = (float(winHeight) - float(texInfo.height) * cfg.scale) / 2.0f;
}
m_Replay->RenderTexture(cfg);
}
}
m_Replay->FlipOutputWindow(m_PreviewOutput);
m_PreviewWindow(true, m_Replay->GetSupportedWindowSystems());
}
}
bool ReplayProxy::Tick(int type)
{
if(!m_RemoteServer)
@@ -1927,6 +2067,8 @@ bool ReplayProxy::Tick(int type)
default: RDCERR("Unexpected command %u", type); return false;
}
RefreshPreviewWindow();
if(m_Writer.IsErrored() || m_Reader.IsErrored() || m_IsErrored)
return false;
+47 -3
View File
@@ -111,20 +111,38 @@ class ReplayProxy : public IReplayDriver
{
public:
ReplayProxy(ReadSerialiser &reader, WriteSerialiser &writer, IReplayDriver *proxy)
: m_Reader(reader), m_Writer(writer), m_Proxy(proxy), m_Remote(NULL), m_RemoteServer(false)
: m_Reader(reader),
m_Writer(writer),
m_Proxy(proxy),
m_Remote(NULL),
m_Replay(NULL),
m_RemoteServer(false)
{
GetAPIProperties();
FetchStructuredFile();
}
ReplayProxy(ReadSerialiser &reader, WriteSerialiser &writer, IRemoteDriver *remote)
: m_Reader(reader), m_Writer(writer), m_Proxy(NULL), m_Remote(remote), m_RemoteServer(true)
ReplayProxy(ReadSerialiser &reader, WriteSerialiser &writer, IRemoteDriver *remoteDriver,
IReplayDriver *replayDriver, RENDERDOC_PreviewWindowCallback previewWindow)
: m_Reader(reader),
m_Writer(writer),
m_Proxy(NULL),
m_Remote(remoteDriver),
m_Replay(replayDriver),
m_PreviewWindow(previewWindow),
m_RemoteServer(true)
{
RDCEraseEl(m_APIProps);
if(m_Replay)
InitPreviewWindow();
}
virtual ~ReplayProxy();
void InitPreviewWindow();
void ShutdownPreviewWindow();
bool IsRemoteProxy() { return !m_RemoteServer; }
void Shutdown() { delete this; }
ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
@@ -394,6 +412,8 @@ public:
return ResourceId();
}
void RefreshPreviewWindow();
bool Tick(int type);
const D3D11Pipe::State &GetD3D11PipelineState() { return m_D3D11PipelineState; }
@@ -521,6 +541,9 @@ private:
void EnsureBufCached(ResourceId bufid);
IMPLEMENT_FUNCTION_PROXIED(bool, NeedRemapForFetch, const ResourceFormat &format);
const DrawcallDescription *FindDraw(const rdcarray<DrawcallDescription> &drawcallList,
uint32_t eventId);
struct TextureCacheEntry
{
ResourceId replayid;
@@ -587,14 +610,35 @@ private:
std::map<ShaderReflKey, ShaderReflection *> m_ShaderReflectionCache;
// reader from the other side of the host <-> remote connection
ReadSerialiser &m_Reader;
// writer to the other side of the host <-> remote connection
WriteSerialiser &m_Writer;
// the local proxy replay driver when on the host side, NULL on the remote server
IReplayDriver *m_Proxy;
// the remote driver on the remote server, NULL on the host side
IRemoteDriver *m_Remote;
// an *optional* replay driver on the remote server, could be NULL if not supported by the system
// on the remote server. Always NULL on the host side.
// This allows us to do some extra things on the remote server such as displaying a preview window
IReplayDriver *m_Replay;
// true if we're the remote server, false if we're the host
bool m_RemoteServer;
// The callback (if provided) that handles creating and ticking a preview window on the remote
// host.
RENDERDOC_PreviewWindowCallback m_PreviewWindow;
// the ID of the output window to use for previewing on the remote host. Only valid/useful if
// m_Replay is set
uint64_t m_PreviewOutput = 0;
uint32_t m_PreviewEvent = 0;
bool m_IsErrored = false;
FrameRecord m_FrameRecord;
APIProperties m_APIProps;
SDFile m_StructuredFile;
+10 -2
View File
@@ -401,7 +401,8 @@ extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_GetDefaultRemoteServerP
}
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_BecomeRemoteServer(
const char *listenhost, uint32_t port, RENDERDOC_KillCallback killReplay)
const char *listenhost, uint32_t port, RENDERDOC_KillCallback killReplay,
RENDERDOC_PreviewWindowCallback previewWindow)
{
if(listenhost == NULL || listenhost[0] == 0)
listenhost = "0.0.0.0";
@@ -410,10 +411,17 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_BecomeRemoteServer(
if(!killReplay)
killReplay = []() { return false; };
// ditto for preview windows
if(!previewWindow)
previewWindow = [](bool, const rdcarray<WindowingSystem> &) {
WindowingData ret = {WindowingSystem::Unknown};
return ret;
};
if(port == 0)
port = RENDERDOC_GetDefaultRemoteServerPort();
RenderDoc::Inst().BecomeRemoteServer(listenhost, (uint16_t)port, killReplay);
RenderDoc::Inst().BecomeRemoteServer(listenhost, (uint16_t)port, killReplay, previewWindow);
}
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartSelfHostCapture(const char *dllname)
+13 -1
View File
@@ -474,6 +474,7 @@ struct RemoteServerCommand : public Command
"host", 'h', "The interface to listen on. By default listens on all interfaces", false, "");
parser.add<uint32_t>("port", 'p', "The port to listen on.", false,
RENDERDOC_GetDefaultRemoteServerPort());
parser.add("preview", 'v', "Display a preview window when a replay is active.");
}
virtual const char *Description()
{
@@ -499,8 +500,19 @@ struct RemoteServerCommand : public Command
usingKillSignal = true;
// by default have a do-nothing callback that creates no windows
RENDERDOC_PreviewWindowCallback previewWindow;
// if the user asked for a preview, then call to the platform-specific preview function
if(parser.exist("preview"))
previewWindow = &DisplayRemoteServerPreview;
// OR if the platform-specific preview function always has a window, then return it anyway.
if(DisplayRemoteServerPreview(false, {}).system != WindowingSystem::Unknown)
previewWindow = &DisplayRemoteServerPreview;
RENDERDOC_BecomeRemoteServer(host.empty() ? NULL : host.c_str(), port,
[]() { return killSignal; });
[]() { return killSignal; }, previewWindow);
std::cerr << std::endl << "Cleaning up from replay hosting." << std::endl;
+1
View File
@@ -57,4 +57,5 @@ void readCapOpts(const std::string &str, CaptureOptions *opts);
// these must be defined in platform .cpps
void DisplayRendererPreview(IReplayController *renderer, TextureDisplay &displayCfg, uint32_t width,
uint32_t height);
WindowingData DisplayRemoteServerPreview(bool active, const rdcarray<WindowingSystem> &systems);
void Daemonise();
+51 -25
View File
@@ -57,31 +57,6 @@ void Daemonise()
{
}
void DisplayRendererPreview(IReplayController *renderer, TextureDisplay &displayCfg, uint32_t width,
uint32_t height)
{
ANativeWindow *connectionScreenWindow = android_state->window;
pthread_mutex_lock(&m_DrawLock.lock);
IReplayOutput *out = renderer->CreateOutput(CreateAndroidWindowingData(connectionScreenWindow),
ReplayOutputType::Texture);
out->SetTextureDisplay(displayCfg);
for(int i = 0; i < 100; i++)
{
renderer->SetFrameEvent(10000000, true);
ANDROID_LOG("Frame %i", i);
out->Display();
usleep(100000);
}
pthread_mutex_unlock(&m_DrawLock.lock);
}
void DisplayGenericSplash()
{
// if something else is drawing and holding the lock, then bail
@@ -269,6 +244,57 @@ void main()
pthread_mutex_unlock(&m_DrawLock.lock);
}
WindowingData DisplayRemoteServerPreview(bool active, const rdcarray<WindowingSystem> &systems)
{
static bool wasActive = false;
// detect when the preview starts or stops
if(wasActive != active)
{
wasActive = active;
// if we're opening it, aquire the draw lock, otherwise release it.
if(active)
{
pthread_mutex_lock(&m_DrawLock.lock);
}
else
{
pthread_mutex_unlock(&m_DrawLock.lock);
// when we release it, re-draw the splash
DisplayGenericSplash();
}
}
return CreateAndroidWindowingData(android_state->window);
}
void DisplayRendererPreview(IReplayController *renderer, TextureDisplay &displayCfg, uint32_t width,
uint32_t height)
{
ANativeWindow *connectionScreenWindow = android_state->window;
pthread_mutex_lock(&m_DrawLock.lock);
IReplayOutput *out = renderer->CreateOutput(CreateAndroidWindowingData(connectionScreenWindow),
ReplayOutputType::Texture);
out->SetTextureDisplay(displayCfg);
for(int i = 0; i < 100; i++)
{
renderer->SetFrameEvent(10000000, true);
ANDROID_LOG("Frame %i", i);
out->Display();
usleep(100000);
}
pthread_mutex_unlock(&m_DrawLock.lock);
}
// Returns the renderdoccmd arguments passed via am start
// Examples: am start ... -e renderdoccmd "remoteserver"
// -e renderdoccmd "replay /sdcard/capture.rdc"
+6
View File
@@ -34,6 +34,12 @@ void Daemonise()
{
}
WindowingData DisplayRemoteServerPreview(bool active, const rdcarray<WindowingSystem> &systems)
{
WindowingData ret = {WindowingSystem::Unknown};
return ret;
}
void DisplayRendererPreview(IReplayController *renderer, TextureDisplay &displayCfg, uint32_t width,
uint32_t height)
{
+114
View File
@@ -202,6 +202,120 @@ void VerifyVulkanLayer(const GlobalEnvironment &env, int argc, char *argv[])
static Display *display = NULL;
WindowingData DisplayRemoteServerPreview(bool active, const rdcarray<WindowingSystem> &systems)
{
static WindowingData remoteServerPreview = {WindowingSystem::Unknown};
// we only have the preview implemented for platforms that have xlib & xcb. It's unlikely
// a meaningful platform exists with only one, and at the time of writing no other windowing
// systems are supported on linux for the replay
#if defined(RENDERDOC_WINDOWING_XLIB) && defined(RENDERDOC_WINDOWING_XCB)
if(active)
{
if(remoteServerPreview.system == WindowingSystem::Unknown)
{
// if we're first initialising, create the window
if(display == NULL)
return remoteServerPreview;
int scr = DefaultScreen(display);
xcb_connection_t *connection = XGetXCBConnection(display);
if(connection == NULL)
{
std::cerr << "Couldn't get XCB connection from Xlib Display" << std::endl;
return remoteServerPreview;
}
XSetEventQueueOwner(display, XCBOwnsEventQueue);
const xcb_setup_t *setup = xcb_get_setup(connection);
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
while(scr-- > 0)
xcb_screen_next(&iter);
xcb_screen_t *screen = iter.data;
uint32_t value_mask, value_list[32];
xcb_window_t window = xcb_generate_id(connection);
value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
value_list[0] = screen->black_pixel;
value_list[1] =
XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY;
xcb_create_window(connection, XCB_COPY_FROM_PARENT, window, screen->root, 0, 0, 1280, 720, 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, value_mask, value_list);
/* Magic code that will send notification when window is destroyed */
xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connection, 1, 12, "WM_PROTOCOLS");
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookie, 0);
xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(connection, 0, 16, "WM_DELETE_WINDOW");
xcb_intern_atom_reply_t *atom_wm_delete_window = xcb_intern_atom_reply(connection, cookie2, 0);
xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window, XCB_ATOM_WM_NAME,
XCB_ATOM_STRING, 8, sizeof("Remote Server Preview") - 1,
"Remote Server Preview");
xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window, (*reply).atom, 4, 32, 1,
&(*atom_wm_delete_window).atom);
free(reply);
xcb_map_window(connection, window);
bool xcb = false, xlib = false;
for(size_t i = 0; i < systems.size(); i++)
{
if(systems[i] == WindowingSystem::Xlib)
xlib = true;
if(systems[i] == WindowingSystem::XCB)
xcb = true;
}
// prefer xcb
if(xcb)
remoteServerPreview = CreateXCBWindowingData(connection, window);
else if(xlib)
remoteServerPreview = CreateXlibWindowingData(display, (Drawable)window);
xcb_flush(connection);
}
else
{
// otherwise, we can pump messages here, but we don't actually care to process any. Just clear
// the queue
xcb_generic_event_t *event = NULL;
xcb_connection_t *connection = remoteServerPreview.xcb.connection;
if(remoteServerPreview.system == WindowingSystem::Xlib)
connection = XGetXCBConnection(remoteServerPreview.xlib.display);
if(connection)
{
do
{
event = xcb_poll_for_event(connection);
if(event)
free(event);
} while(event);
}
}
}
else
{
// reset the windowing data to 'no window'
remoteServerPreview = {WindowingSystem::Unknown};
}
#endif
return remoteServerPreview;
}
void DisplayRendererPreview(IReplayController *renderer, TextureDisplay &displayCfg, uint32_t width,
uint32_t height)
{
+55
View File
@@ -128,6 +128,61 @@ void Daemonise()
// nothing really to do, windows version of renderdoccmd is already 'detached'
}
WindowingData DisplayRemoteServerPreview(bool active, const rdcarray<WindowingSystem> &systems)
{
static WindowingData remoteServerPreview = {WindowingSystem::Unknown};
if(active)
{
if(remoteServerPreview.system == WindowingSystem::Unknown)
{
// if we're first initialising, create the window
RECT wr = {0, 0, (LONG)1280, (LONG)720};
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
HWND wnd =
CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdoccmd", L"Remote Server Preview",
WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT,
wr.right - wr.left, wr.bottom - wr.top, NULL, NULL, hInstance, NULL);
if(wnd == NULL)
return remoteServerPreview;
ShowWindow(wnd, SW_SHOW);
UpdateWindow(wnd);
remoteServerPreview.system = WindowingSystem::Win32;
remoteServerPreview.win32.window = wnd;
}
else
{
// otherwise, pump messages
MSG msg;
ZeroMemory(&msg, sizeof(msg));
// Check to see if any messages are waiting in the queue
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// Translate the message and dispatch it to WindowProc()
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
else
{
// if we had a previous window, destroy it.
if(remoteServerPreview.win32.window != NULL)
DestroyWindow(remoteServerPreview.win32.window);
// reset the windowing data to 'no window'
remoteServerPreview = {WindowingSystem::Unknown};
}
return remoteServerPreview;
}
void DisplayRendererPreview(IReplayController *renderer, TextureDisplay &displayCfg, uint32_t width,
uint32_t height)
{