Tweak how device/window handles work with NULL, to now wildcard match

* This makes it a bit easier to specify what you want to capture without
  requiring redundant information.
This commit is contained in:
baldurk
2015-06-20 16:09:39 +02:00
parent adaf3b25e6
commit b7fd43f237
5 changed files with 104 additions and 76 deletions
+17 -2
View File
@@ -244,11 +244,26 @@ typedef uint32_t (RENDERDOC_CC *pRENDERDOC_GetCapture)(uint32_t idx, char *logfi
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SetCaptureOptions(const CaptureOptions *opts);
typedef void (RENDERDOC_CC *pRENDERDOC_SetCaptureOptions)(const CaptureOptions *opts);
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_TriggerCapture();
typedef void (RENDERDOC_CC *pRENDERDOC_TriggerCapture)();
// In the below functions 'device pointer' corresponds to the API specific handle, e.g.
// ID3D11Device, or the GL context pointer.
// The 'window handle' is the OS's native window handle (HWND or GLXDrawable).
// This must match precisely to a pair, and it sets the RenderDoc in-app overlay to select that
// window as 'active' and respond to keypresses.
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SetActiveWindow(void *device, void *wndHandle);
typedef void (RENDERDOC_CC *pRENDERDOC_SetActiveWindow)(void *device, void *wndHandle);
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_TriggerCapture();
typedef void (RENDERDOC_CC *pRENDERDOC_TriggerCapture)();
// Either parameter can be NULL to wild-card match, such that you can capture from any
// device to a particular window, or a particular device to any window.
// In either case, if there are two or more possible matching (device,window) pairs it
// is undefined which one will be captured.
// You can pass (NULL, NULL) if you know you only have one device and one window, and
// it will match. Likewise if you have not created a window at all (only off-screen
// rendering), then NULL window pointer will capture, whether you pass a NULL device
// or specify a device among multiple.
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartFrameCapture(void *device, void *wndHandle);
typedef void (RENDERDOC_CC *pRENDERDOC_StartFrameCapture)(void *device, void *wndHandle);
+62 -63
View File
@@ -30,6 +30,8 @@
#include <time.h>
#include <algorithm>
#include "data/version.h"
#include "crash_handler.h"
@@ -310,39 +312,51 @@ void RenderDoc::Shutdown()
}
}
void RenderDoc::StartFrameCapture(void *dev, void *wnd)
IFrameCapturer *RenderDoc::MatchFrameCapturer(void *dev, void *wnd)
{
if(dev == NULL || wnd == NULL)
{
// if we have a single window frame capturer, use that in preference
if(m_WindowFrameCapturers.size() == 1)
{
auto it = m_WindowFrameCapturers.begin();
it->second.FrameCapturer->StartFrameCapture(it->first.dev, it->first.wnd);
}
// otherwise, see if we only have one default capturer
else if(m_DefaultFrameCapturers.size() == 1)
{
(*m_DefaultFrameCapturers.begin())->StartFrameCapture(dev, wnd);
}
// otherwise we can't capture with NULL handles
else
{
RDCERR("Multiple frame capture methods registered, can't capture by NULL handles");
}
return;
}
DeviceWnd dw(dev, wnd);
auto it = m_WindowFrameCapturers.find(dw);
if(it == m_WindowFrameCapturers.end())
// lower_bound and the DeviceWnd ordering (pointer compares, dev over wnd) means that if either
// element in dw is NULL we can go forward from this iterator and find the first wildcardMatch
// note that if dev is specified and wnd is NULL, this will actually point at the first
// wildcardMatch already and we can use it immediately (since which window of multiple we
// choose is undefined, so up to us). If dev is NULL there is no window ordering (since dev is
// the primary sorting value) so we just iterate through the whole map. It should be small in
// the majority of cases
auto it = m_WindowFrameCapturers.lower_bound(dw);
while(it != m_WindowFrameCapturers.end())
{
RDCERR("Couldn't find frame capturer for device %p window %p", dev, wnd);
return;
if(it->first.wildcardMatch(dw)) break;
++it;
}
it->second.FrameCapturer->StartFrameCapture(dev, wnd);
if(it == m_WindowFrameCapturers.end())
{
// handle off-screen rendering where there are no device/window pairs in
// m_WindowFrameCapturers, instead we use the first matching device frame capturer
if(wnd == NULL)
{
auto defaultit = m_DeviceFrameCapturers.find(dev);
if(defaultit == m_DeviceFrameCapturers.end() && !m_DeviceFrameCapturers.empty())
defaultit = m_DeviceFrameCapturers.begin();
if(defaultit != m_DeviceFrameCapturers.end())
return defaultit->second;
}
RDCERR("Couldn't find matching frame capturer for device %p window %p", dev, wnd);
return NULL;
}
return it->second.FrameCapturer;
}
void RenderDoc::StartFrameCapture(void *dev, void *wnd)
{
IFrameCapturer *frameCap = MatchFrameCapturer(dev, wnd);
if(frameCap)
frameCap->StartFrameCapture(dev, wnd);
}
void RenderDoc::SetActiveWindow(void *dev, void *wnd)
@@ -361,37 +375,10 @@ void RenderDoc::SetActiveWindow(void *dev, void *wnd)
bool RenderDoc::EndFrameCapture(void *dev, void *wnd)
{
if(dev == NULL || wnd == NULL)
{
// if we have a single window frame capturer, use that in preference
if(m_WindowFrameCapturers.size() == 1)
{
auto it = m_WindowFrameCapturers.begin();
return it->second.FrameCapturer->EndFrameCapture(it->first.dev, it->first.wnd);
}
// otherwise, see if we only have one default capturer
else if(m_DefaultFrameCapturers.size() == 1)
{
(*m_DefaultFrameCapturers.begin())->EndFrameCapture(dev, wnd);
}
// otherwise we can't capture with NULL handles
else
{
RDCERR("Multiple frame capture methods registered, can't capture by NULL handles");
}
return false;
}
DeviceWnd dw(dev, wnd);
auto it = m_WindowFrameCapturers.find(dw);
if(it == m_WindowFrameCapturers.end())
{
RDCERR("Couldn't find frame capturer for device %p, window %p", dev, wnd);
return false;
}
return it->second.FrameCapturer->EndFrameCapture(dev, wnd);
IFrameCapturer *frameCap = MatchFrameCapturer(dev, wnd);
if(frameCap)
return frameCap->EndFrameCapture(dev, wnd);
return false;
}
bool RenderDoc::IsRemoteAccessConnected()
@@ -779,14 +766,26 @@ void RenderDoc::SuccessfullyWrittenLog()
}
}
void RenderDoc::AddDefaultFrameCapturer(IFrameCapturer *cap)
void RenderDoc::AddDeviceFrameCapturer(void *dev, IFrameCapturer *cap)
{
m_DefaultFrameCapturers.insert(cap);
if(dev == NULL || cap == NULL)
{
RDCERR("Invalid FrameCapturer combination: %#p / %#p", dev, cap);
return;
}
m_DeviceFrameCapturers[dev] = cap;
}
void RenderDoc::RemoveDefaultFrameCapturer(IFrameCapturer *cap)
void RenderDoc::RemoveDeviceFrameCapturer(void *dev)
{
m_DefaultFrameCapturers.erase(cap);
if(dev == NULL)
{
RDCERR("Invalid device pointer: %#p / %#p", dev);
return;
}
m_DeviceFrameCapturers.erase(dev);
}
void RenderDoc::AddFrameCapturer(void *dev, void *wnd, IFrameCapturer *cap)
@@ -803,7 +802,7 @@ void RenderDoc::AddFrameCapturer(void *dev, void *wnd, IFrameCapturer *cap)
if(it != m_WindowFrameCapturers.end())
{
if(it->second.FrameCapturer != cap)
RDCERR("New different FrameCapturer being registered for known window!");
RDCERR("New different FrameCapturer being registered for known device/window pair!");
it->second.RefCount++;
}
+17 -3
View File
@@ -241,8 +241,8 @@ class RenderDoc
// add window-less frame capturers for use via users capturing
// manually through the renderdoc API with NULL device/window handles
void AddDefaultFrameCapturer(IFrameCapturer *cap);
void RemoveDefaultFrameCapturer(IFrameCapturer *cap);
void AddDeviceFrameCapturer(void *dev, IFrameCapturer *cap);
void RemoveDeviceFrameCapturer(void *dev);
void StartFrameCapture(void *dev, void *wnd);
void SetActiveWindow(void *dev, void *wnd);
@@ -334,16 +334,30 @@ class RenderDoc
{
return dev == o.dev && wnd == o.wnd;
}
bool operator <(const DeviceWnd &o) const
{
if(dev != o.dev) return dev < o.dev;
return wnd < o.wnd;
}
bool wildcardMatch(const DeviceWnd &o) const
{
if(dev == NULL || o.dev == NULL)
return wnd == NULL || o.wnd == NULL || wnd == o.wnd;
if(wnd == NULL || o.wnd == NULL)
return dev == NULL || o.dev == NULL || dev == o.dev;
return *this == o;
}
};
map<DeviceWnd, FrameCap> m_WindowFrameCapturers;
DeviceWnd m_ActiveWindow;
set<IFrameCapturer *> m_DefaultFrameCapturers;
map<void *, IFrameCapturer *> m_DeviceFrameCapturers;
IFrameCapturer *MatchFrameCapturer(void *dev, void *wnd);
volatile bool m_RemoteServerThreadShutdown;
volatile bool m_RemoteClientThreadShutdown;
+2 -2
View File
@@ -342,7 +342,7 @@ WrappedID3D11Device::WrappedID3D11Device(ID3D11Device* realDevice, D3D11InitPara
m_DeviceRecord->NumSubResources = 0;
m_DeviceRecord->SubResources = NULL;
RenderDoc::Inst().AddDefaultFrameCapturer(this);
RenderDoc::Inst().AddDeviceFrameCapturer((ID3D11Device *)this, this);
}
ID3D11DeviceContext *context = NULL;
@@ -416,7 +416,7 @@ WrappedID3D11Device::~WrappedID3D11Device()
if(m_pCurrentWrappedDevice == this)
m_pCurrentWrappedDevice = NULL;
RenderDoc::Inst().RemoveDefaultFrameCapturer(this);
RenderDoc::Inst().RemoveDeviceFrameCapturer((ID3D11Device *)this);
for(auto it = m_CachedStateObjects.begin(); it != m_CachedStateObjects.end(); ++it)
if(*it)
+6 -6
View File
@@ -760,8 +760,6 @@ WrappedOpenGL::WrappedOpenGL(const char *logfile, const GLHookSet &funcs)
m_FakeVAOID = GetResourceManager()->RegisterResource(VertexArrayRes(NULL, 0));
GetResourceManager()->AddResourceRecord(m_FakeVAOID);
GetResourceManager()->MarkDirtyResource(m_FakeVAOID);
RenderDoc::Inst().AddDefaultFrameCapturer(this);
}
else
{
@@ -909,8 +907,6 @@ WrappedOpenGL::~WrappedOpenGL()
if(m_FakeBB_Color) m_Real.glDeleteTextures(1, &m_FakeBB_Color);
if(m_FakeBB_DepthStencil) m_Real.glDeleteTextures(1, &m_FakeBB_DepthStencil);
RenderDoc::Inst().RemoveDefaultFrameCapturer(this);
SAFE_DELETE(m_pSerialiser);
GetResourceManager()->ReleaseCurrentResource(m_DeviceResourceID);
@@ -962,6 +958,8 @@ void WrappedOpenGL::DeleteContext(void *contextHandle)
{
ContextData &ctxdata = m_ContextData[contextHandle];
RenderDoc::Inst().RemoveDeviceFrameCapturer(ctxdata.ctx);
if(ctxdata.built && ctxdata.ready)
{
if(ctxdata.Program)
@@ -1007,6 +1005,8 @@ void WrappedOpenGL::CreateContext(GLWindowingData winData, void *shareContext, G
ctxdata.ctx = winData.ctx;
ctxdata.isCore = core;
ctxdata.attribsCreate = attribsCreate;
RenderDoc::Inst().AddDeviceFrameCapturer(ctxdata.ctx, this);
}
void WrappedOpenGL::RegisterContext(GLWindowingData winData, void *shareContext, bool core, bool attribsCreate)
@@ -2186,7 +2186,7 @@ void WrappedOpenGL::SwapBuffers(void *windowHandle)
// kill any current capture that isn't application defined
if(m_State == WRITING_CAPFRAME && !m_AppControlledCapture)
EndFrameCapture(this, windowHandle);
EndFrameCapture(ctxdata.ctx, windowHandle);
// for now, only allow one captured frame at all
if(!m_FrameRecord.empty())
@@ -2194,7 +2194,7 @@ void WrappedOpenGL::SwapBuffers(void *windowHandle)
if(RenderDoc::Inst().ShouldTriggerCapture(m_FrameCounter) && m_State == WRITING_IDLE)
{
StartFrameCapture(this, windowHandle);
StartFrameCapture(ctxdata.ctx, windowHandle);
m_AppControlledCapture = false;
}