mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-29 21:30:53 +00:00
Support switching between multiple APIs in the same program. Closes #124
* The core class is now responsible for tracking the active window and cycling through, so it can cycle through multiple APIs. * For GL we only set up associations for capturable windows, and only those that present (since helper windows are often created). Since GL doesn't really have a 'this window is done rendering' call, we just decay old windows that haven't presented in >5 seconds. * Also on GL, legacy/uncapturable windows aren't associated so they will not cycle to at all. * The embedding API now expects a device pointer and window handle to set active window or start/end a capture. You can still pass NULLs if there is only one API active.
This commit is contained in:
@@ -226,7 +226,12 @@ enum InAppOverlay
|
||||
|
||||
// API breaking change history:
|
||||
// Version 1 -> 2 - strings changed from wchar_t* to char* (UTF-8)
|
||||
#define RENDERDOC_API_VERSION 2
|
||||
// Version 2 -> 3 - StartFrameCapture, EndFrameCapture and SetActiveWindow take
|
||||
// 'device' pointer as well as window handles.
|
||||
// This is either ID3D11Device* or the GL context (HGLRC/GLXContext)
|
||||
// You can still pass NULL to both to capture the default, as long as
|
||||
// there's only one device/window pair alive.
|
||||
#define RENDERDOC_API_VERSION 3
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// In-program functions
|
||||
@@ -250,17 +255,17 @@ typedef bool32 (RENDERDOC_CC *pRENDERDOC_GetCapture)(uint32_t idx, char *logfile
|
||||
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_SetActiveWindow(void *wndHandle);
|
||||
typedef void (RENDERDOC_CC *pRENDERDOC_SetActiveWindow)(void *wndHandle);
|
||||
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)();
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartFrameCapture(void *wndHandle);
|
||||
typedef void (RENDERDOC_CC *pRENDERDOC_StartFrameCapture)(void *wndHandle);
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartFrameCapture(void *device, void *wndHandle);
|
||||
typedef void (RENDERDOC_CC *pRENDERDOC_StartFrameCapture)(void *device, void *wndHandle);
|
||||
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC RENDERDOC_EndFrameCapture(void *wndHandle);
|
||||
typedef bool32 (RENDERDOC_CC *pRENDERDOC_EndFrameCapture)(void *wndHandle);
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC RENDERDOC_EndFrameCapture(void *device, void *wndHandle);
|
||||
typedef bool32 (RENDERDOC_CC *pRENDERDOC_EndFrameCapture)(void *device, void *wndHandle);
|
||||
|
||||
extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_GetOverlayBits();
|
||||
typedef uint32_t (RENDERDOC_CC *pRENDERDOC_GetOverlayBits)();
|
||||
|
||||
+99
-27
@@ -160,7 +160,6 @@ RenderDoc::RenderDoc()
|
||||
|
||||
m_Replay = false;
|
||||
|
||||
m_Focus = false;
|
||||
m_Cap = false;
|
||||
|
||||
m_FocusKeys.clear();
|
||||
@@ -311,66 +310,88 @@ void RenderDoc::Shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
void RenderDoc::StartFrameCapture(void *wnd)
|
||||
void RenderDoc::StartFrameCapture(void *dev, void *wnd)
|
||||
{
|
||||
if(wnd == NULL)
|
||||
if(dev == NULL || wnd == NULL)
|
||||
{
|
||||
// if we have a single window frame capturer, use that in preference
|
||||
if(m_WindowFrameCapturers.size() == 1)
|
||||
{
|
||||
m_WindowFrameCapturers.begin()->second.FrameCapturer->StartFrameCapture(wnd);
|
||||
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 window");
|
||||
RDCERR("Multiple frame capture methods registered, can't capture by NULL handles");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = m_WindowFrameCapturers.find(wnd);
|
||||
DeviceWnd dw(dev, wnd);
|
||||
|
||||
auto it = m_WindowFrameCapturers.find(dw);
|
||||
if(it == m_WindowFrameCapturers.end())
|
||||
{
|
||||
RDCERR("Couldn't find frame capturer for this window %p", wnd);
|
||||
RDCERR("Couldn't find frame capturer for device %p window %p", dev, wnd);
|
||||
return;
|
||||
}
|
||||
|
||||
it->second.FrameCapturer->StartFrameCapture(wnd);
|
||||
it->second.FrameCapturer->StartFrameCapture(dev, wnd);
|
||||
}
|
||||
|
||||
void RenderDoc::SetActiveWindow(void *wnd)
|
||||
void RenderDoc::SetActiveWindow(void *dev, void *wnd)
|
||||
{
|
||||
auto it = m_WindowFrameCapturers.find(wnd);
|
||||
DeviceWnd dw(dev, wnd);
|
||||
|
||||
auto it = m_WindowFrameCapturers.find(dw);
|
||||
if(it == m_WindowFrameCapturers.end())
|
||||
{
|
||||
RDCERR("Couldn't find frame capturer for this window %p", wnd);
|
||||
RDCERR("Couldn't find frame capturer for device %p window %p", dev, wnd);
|
||||
return;
|
||||
}
|
||||
|
||||
it->second.FrameCapturer->SetActiveWindow(wnd);
|
||||
m_ActiveWindow = dw;
|
||||
}
|
||||
|
||||
bool RenderDoc::EndFrameCapture(void *wnd)
|
||||
bool RenderDoc::EndFrameCapture(void *dev, void *wnd)
|
||||
{
|
||||
if(wnd == NULL)
|
||||
if(dev == NULL || wnd == NULL)
|
||||
{
|
||||
// if we have a single window frame capturer, use that in preference
|
||||
if(m_WindowFrameCapturers.size() == 1)
|
||||
{
|
||||
return m_WindowFrameCapturers.begin()->second.FrameCapturer->EndFrameCapture(wnd);
|
||||
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 window");
|
||||
RDCERR("Multiple frame capture methods registered, can't capture by NULL handles");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it = m_WindowFrameCapturers.find(wnd);
|
||||
DeviceWnd dw(dev, wnd);
|
||||
|
||||
auto it = m_WindowFrameCapturers.find(dw);
|
||||
if(it == m_WindowFrameCapturers.end())
|
||||
{
|
||||
RDCERR("Couldn't find frame capturer for this window %p", wnd);
|
||||
RDCERR("Couldn't find frame capturer for device %p, window %p", dev, wnd);
|
||||
return false;
|
||||
}
|
||||
|
||||
return it->second.FrameCapturer->EndFrameCapture(wnd);
|
||||
return it->second.FrameCapturer->EndFrameCapture(dev, wnd);
|
||||
}
|
||||
|
||||
void RenderDoc::Tick()
|
||||
@@ -385,9 +406,32 @@ void RenderDoc::Tick()
|
||||
for(size_t i=0; i < m_CaptureKeys.size(); i++) cur_cap |= Keyboard::GetKeyState(m_CaptureKeys[i]);
|
||||
|
||||
if(!prev_focus && cur_focus)
|
||||
FocusToggle();
|
||||
{
|
||||
m_Cap = false;
|
||||
|
||||
// can only shift focus if we have multiple windows
|
||||
if(m_WindowFrameCapturers.size() > 1)
|
||||
{
|
||||
for(auto it = m_WindowFrameCapturers.begin(); it != m_WindowFrameCapturers.end(); ++it)
|
||||
{
|
||||
if(it->first == m_ActiveWindow)
|
||||
{
|
||||
auto nextit = it; ++nextit;
|
||||
|
||||
if(nextit != m_WindowFrameCapturers.end())
|
||||
m_ActiveWindow = nextit->first;
|
||||
else
|
||||
m_ActiveWindow = m_WindowFrameCapturers.begin()->first;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!prev_cap && cur_cap)
|
||||
TriggerCapture();
|
||||
{
|
||||
TriggerCapture();
|
||||
}
|
||||
|
||||
prev_focus = cur_focus;
|
||||
prev_cap = cur_cap;
|
||||
@@ -729,15 +773,27 @@ void RenderDoc::SuccessfullyWrittenLog()
|
||||
}
|
||||
}
|
||||
|
||||
void RenderDoc::AddFrameCapturer(void *wnd, IFrameCapturer *cap)
|
||||
void RenderDoc::AddDefaultFrameCapturer(IFrameCapturer *cap)
|
||||
{
|
||||
if(wnd == NULL || cap == NULL)
|
||||
m_DefaultFrameCapturers.insert(cap);
|
||||
}
|
||||
|
||||
void RenderDoc::RemoveDefaultFrameCapturer(IFrameCapturer *cap)
|
||||
{
|
||||
m_DefaultFrameCapturers.erase(cap);
|
||||
}
|
||||
|
||||
void RenderDoc::AddFrameCapturer(void *dev, void *wnd, IFrameCapturer *cap)
|
||||
{
|
||||
if(dev == NULL || wnd == NULL || cap == NULL)
|
||||
{
|
||||
RDCERR("Invalid FrameCapturer combination: %#p / %#p", wnd, cap);
|
||||
return;
|
||||
}
|
||||
|
||||
DeviceWnd dw(dev, wnd);
|
||||
|
||||
auto it = m_WindowFrameCapturers.find(wnd);
|
||||
auto it = m_WindowFrameCapturers.find(dw);
|
||||
if(it != m_WindowFrameCapturers.end())
|
||||
{
|
||||
if(it->second.FrameCapturer != cap)
|
||||
@@ -747,19 +803,35 @@ void RenderDoc::AddFrameCapturer(void *wnd, IFrameCapturer *cap)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_WindowFrameCapturers[wnd].FrameCapturer = cap;
|
||||
m_WindowFrameCapturers[dw].FrameCapturer = cap;
|
||||
}
|
||||
|
||||
// the first one we see becomes the default
|
||||
if(m_ActiveWindow == DeviceWnd())
|
||||
m_ActiveWindow = dw;
|
||||
}
|
||||
|
||||
void RenderDoc::RemoveFrameCapturer(void *wnd)
|
||||
void RenderDoc::RemoveFrameCapturer(void *dev, void *wnd)
|
||||
{
|
||||
auto it = m_WindowFrameCapturers.find(wnd);
|
||||
DeviceWnd dw(dev, wnd);
|
||||
|
||||
auto it = m_WindowFrameCapturers.find(dw);
|
||||
if(it != m_WindowFrameCapturers.end())
|
||||
{
|
||||
it->second.RefCount--;
|
||||
|
||||
if(it->second.RefCount <= 0)
|
||||
{
|
||||
if(m_ActiveWindow == dw)
|
||||
{
|
||||
if(m_WindowFrameCapturers.size() == 1)
|
||||
m_ActiveWindow = DeviceWnd();
|
||||
else
|
||||
m_ActiveWindow = m_WindowFrameCapturers.begin()->first;
|
||||
}
|
||||
|
||||
m_WindowFrameCapturers.erase(it);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+36
-13
@@ -62,9 +62,8 @@ struct ICrashHandler
|
||||
|
||||
struct IFrameCapturer
|
||||
{
|
||||
virtual void StartFrameCapture(void *wnd) = 0;
|
||||
virtual void SetActiveWindow(void *wnd) = 0;
|
||||
virtual bool EndFrameCapture(void *wnd) = 0;
|
||||
virtual void StartFrameCapture(void *dev, void *wnd) = 0;
|
||||
virtual bool EndFrameCapture(void *dev, void *wnd) = 0;
|
||||
};
|
||||
|
||||
enum LogState
|
||||
@@ -236,14 +235,20 @@ class RenderDoc
|
||||
|
||||
void Tick();
|
||||
|
||||
void AddFrameCapturer(void *wnd, IFrameCapturer *cap);
|
||||
void RemoveFrameCapturer(void *wnd);
|
||||
|
||||
void StartFrameCapture(void *wnd);
|
||||
void SetActiveWindow(void *wnd);
|
||||
bool EndFrameCapture(void *wnd);
|
||||
void AddFrameCapturer(void *dev, void *wnd, IFrameCapturer *cap);
|
||||
void RemoveFrameCapturer(void *dev, void *wnd);
|
||||
|
||||
// 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 StartFrameCapture(void *dev, void *wnd);
|
||||
void SetActiveWindow(void *dev, void *wnd);
|
||||
bool EndFrameCapture(void *dev, void *wnd);
|
||||
|
||||
bool IsActiveWindow(void *dev, void *wnd) { return dev == m_ActiveWindow.dev && wnd == m_ActiveWindow.wnd; }
|
||||
|
||||
void FocusToggle() { m_Focus = true; m_Cap = false; }
|
||||
void TriggerCapture() { m_Cap = true; }
|
||||
|
||||
uint32_t GetOverlayBits() { return m_Overlay; }
|
||||
@@ -267,7 +272,6 @@ class RenderDoc
|
||||
const vector<KeyButton> &GetFocusKeys() { return m_FocusKeys; }
|
||||
const vector<KeyButton> &GetCaptureKeys() { return m_CaptureKeys; }
|
||||
|
||||
bool ShouldFocusToggle() { bool ret = m_Focus; m_Focus = false; return ret; }
|
||||
bool ShouldTriggerCapture(uint32_t frameNumber);
|
||||
private:
|
||||
RenderDoc();
|
||||
@@ -277,7 +281,6 @@ class RenderDoc
|
||||
|
||||
bool m_Replay;
|
||||
|
||||
bool m_Focus;
|
||||
bool m_Cap;
|
||||
|
||||
vector<KeyButton> m_FocusKeys;
|
||||
@@ -319,7 +322,27 @@ class RenderDoc
|
||||
int RefCount;
|
||||
};
|
||||
|
||||
map<void*, FrameCap> m_WindowFrameCapturers;
|
||||
struct DeviceWnd
|
||||
{
|
||||
DeviceWnd() : dev(NULL), wnd(NULL) {}
|
||||
DeviceWnd(void *d, void *w) : dev(d), wnd(w) {}
|
||||
void *dev;
|
||||
void *wnd;
|
||||
|
||||
bool operator ==(const DeviceWnd &o) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
map<DeviceWnd, FrameCap> m_WindowFrameCapturers;
|
||||
DeviceWnd m_ActiveWindow;
|
||||
set<IFrameCapturer *> m_DefaultFrameCapturers;
|
||||
|
||||
volatile bool m_RemoteServerThreadShutdown;
|
||||
volatile bool m_RemoteClientThreadShutdown;
|
||||
|
||||
@@ -288,8 +288,6 @@ WrappedID3D11Device::WrappedID3D11Device(ID3D11Device* realDevice, D3D11InitPara
|
||||
m_FailedReason = CaptureSucceeded;
|
||||
m_Failures = 0;
|
||||
|
||||
m_SwapChain = NULL;
|
||||
|
||||
m_FrameTimer.Restart();
|
||||
|
||||
m_AppControlledCapture = false;
|
||||
@@ -343,7 +341,7 @@ WrappedID3D11Device::WrappedID3D11Device(ID3D11Device* realDevice, D3D11InitPara
|
||||
m_DeviceRecord->NumSubResources = 0;
|
||||
m_DeviceRecord->SubResources = NULL;
|
||||
|
||||
RenderDoc::Inst().AddFrameCapturer(this, this);
|
||||
RenderDoc::Inst().AddDefaultFrameCapturer(this);
|
||||
}
|
||||
|
||||
ID3D11DeviceContext *context = NULL;
|
||||
@@ -417,6 +415,8 @@ WrappedID3D11Device::~WrappedID3D11Device()
|
||||
if(m_pCurrentWrappedDevice == this)
|
||||
m_pCurrentWrappedDevice = NULL;
|
||||
|
||||
RenderDoc::Inst().RemoveDefaultFrameCapturer(this);
|
||||
|
||||
for(auto it = m_CachedStateObjects.begin(); it != m_CachedStateObjects.end(); ++it)
|
||||
if(*it)
|
||||
(*it)->Release();
|
||||
@@ -456,9 +456,6 @@ WrappedID3D11Device::~WrappedID3D11Device()
|
||||
SAFE_DELETE(it->second);
|
||||
m_LayoutDXBC.clear();
|
||||
m_LayoutDescs.clear();
|
||||
|
||||
if(!RenderDoc::Inst().IsReplayApp())
|
||||
RenderDoc::Inst().RemoveFrameCapturer(this);
|
||||
|
||||
if(RenderDoc::Inst().GetCrashHandler())
|
||||
RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this);
|
||||
@@ -2327,6 +2324,8 @@ void WrappedID3D11Device::ReleaseSwapchainResources(IDXGISwapChain *swap)
|
||||
swap->GetDesc(&desc);
|
||||
|
||||
Keyboard::RemoveInputWindow(desc.OutputWindow);
|
||||
|
||||
RenderDoc::Inst().RemoveFrameCapturer(this, desc.OutputWindow);
|
||||
}
|
||||
|
||||
auto it = m_SwapChains.find(swap);
|
||||
@@ -2335,14 +2334,6 @@ void WrappedID3D11Device::ReleaseSwapchainResources(IDXGISwapChain *swap)
|
||||
SAFE_RELEASE(it->second);
|
||||
m_SwapChains.erase(it);
|
||||
}
|
||||
|
||||
if(swap == m_SwapChain)
|
||||
{
|
||||
if(m_SwapChains.empty())
|
||||
m_SwapChain = NULL;
|
||||
else
|
||||
m_SwapChain = m_SwapChains.begin()->first;
|
||||
}
|
||||
}
|
||||
|
||||
bool WrappedID3D11Device::Serialise_SetSwapChainTexture(IDXGISwapChain *swap, DXGI_SWAP_CHAIN_DESC *swapDesc, UINT buffer, ID3D11Texture2D *pTex)
|
||||
@@ -2442,11 +2433,8 @@ void WrappedID3D11Device::SetSwapChainTexture(IDXGISwapChain *swap, DXGI_SWAP_CH
|
||||
swap->GetDesc(&sdesc);
|
||||
|
||||
Keyboard::AddInputWindow(sdesc.OutputWindow);
|
||||
}
|
||||
|
||||
if(m_SwapChain == NULL)
|
||||
{
|
||||
m_SwapChain = swap;
|
||||
RenderDoc::Inst().AddFrameCapturer(this, sdesc.OutputWindow, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2474,7 +2462,7 @@ int WrappedID3D11Device::EndEvent()
|
||||
return m_pCurrentWrappedDevice->m_pImmediateContext->ThreadSafe_EndEvent();
|
||||
}
|
||||
|
||||
void WrappedID3D11Device::StartFrameCapture(void *wnd)
|
||||
void WrappedID3D11Device::StartFrameCapture(void *dev, void *wnd)
|
||||
{
|
||||
if(m_State != WRITING_IDLE) return;
|
||||
|
||||
@@ -2526,24 +2514,7 @@ void WrappedID3D11Device::StartFrameCapture(void *wnd)
|
||||
RDCLOG("Starting capture, frame %u", m_FrameCounter);
|
||||
}
|
||||
|
||||
void WrappedID3D11Device::SetActiveWindow(void *wnd)
|
||||
{
|
||||
for(auto it=m_SwapChains.begin(); it!=m_SwapChains.end(); ++it)
|
||||
{
|
||||
DXGI_SWAP_CHAIN_DESC swapDesc;
|
||||
it->first->GetDesc(&swapDesc);
|
||||
|
||||
if(swapDesc.OutputWindow == wnd)
|
||||
{
|
||||
m_SwapChain = it->first;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RDCERR("Output window %p provided for active window corresponds with no known swap chain", wnd);
|
||||
}
|
||||
|
||||
bool WrappedID3D11Device::EndFrameCapture(void *wnd)
|
||||
bool WrappedID3D11Device::EndFrameCapture(void *dev, void *wnd)
|
||||
{
|
||||
if(m_State != WRITING_CAPFRAME) return true;
|
||||
|
||||
@@ -2996,7 +2967,6 @@ HRESULT WrappedID3D11Device::Present(IDXGISwapChain *swap, UINT SyncInterval, UI
|
||||
if((Flags & DXGI_PRESENT_TEST) != 0)
|
||||
return S_OK;
|
||||
|
||||
RenderDoc::Inst().SetCurrentDriver(RDC_D3D11);
|
||||
m_pCurrentWrappedDevice = this;
|
||||
|
||||
if(m_State == WRITING_IDLE)
|
||||
@@ -3008,6 +2978,10 @@ HRESULT WrappedID3D11Device::Present(IDXGISwapChain *swap, UINT SyncInterval, UI
|
||||
|
||||
m_pImmediateContext->BeginFrame();
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC swapdesc;
|
||||
swap->GetDesc(&swapdesc);
|
||||
bool activeWindow = RenderDoc::Inst().IsActiveWindow(this, swapdesc.OutputWindow);
|
||||
|
||||
if(m_State == WRITING_IDLE)
|
||||
{
|
||||
D3D11RenderState old = *m_pImmediateContext->GetCurrentPipelineState();
|
||||
@@ -3055,7 +3029,7 @@ HRESULT WrappedID3D11Device::Present(IDXGISwapChain *swap, UINT SyncInterval, UI
|
||||
GetDebugManager()->SetOutputDimensions(swapDesc.BufferDesc.Width, swapDesc.BufferDesc.Height);
|
||||
GetDebugManager()->SetOutputWindow(swapDesc.OutputWindow);
|
||||
|
||||
if(swap == m_SwapChain)
|
||||
if(activeWindow)
|
||||
{
|
||||
vector<KeyButton> keys = RenderDoc::Inst().GetCaptureKeys();
|
||||
|
||||
@@ -3131,7 +3105,7 @@ HRESULT WrappedID3D11Device::Present(IDXGISwapChain *swap, UINT SyncInterval, UI
|
||||
{
|
||||
vector<KeyButton> keys = RenderDoc::Inst().GetFocusKeys();
|
||||
|
||||
string str = "Inactive swapchain.";
|
||||
string str = "D3D11. Inactive swapchain.";
|
||||
|
||||
for(size_t i=0; i < keys.size(); i++)
|
||||
{
|
||||
@@ -3151,48 +3125,20 @@ HRESULT WrappedID3D11Device::Present(IDXGISwapChain *swap, UINT SyncInterval, UI
|
||||
|
||||
old.ApplyState(m_pImmediateContext);
|
||||
}
|
||||
|
||||
if(RenderDoc::Inst().ShouldFocusToggle())
|
||||
{
|
||||
IDXGISwapChain *s = m_SwapChain;
|
||||
m_SwapChain = NULL;
|
||||
|
||||
for(auto it=m_SwapChains.begin(); it!=m_SwapChains.end(); ++it)
|
||||
{
|
||||
auto next = it; next++;
|
||||
if(it->first == s)
|
||||
{
|
||||
if(next != m_SwapChains.end())
|
||||
m_SwapChain = next->first;
|
||||
else
|
||||
m_SwapChain = m_SwapChains.begin()->first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_SwapChain == NULL)
|
||||
m_SwapChain = swap;
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC swapDesc = {0};
|
||||
m_SwapChain->GetDesc(&swapDesc);
|
||||
GetDebugManager()->SetOutputDimensions(swapDesc.BufferDesc.Width, swapDesc.BufferDesc.Height);
|
||||
GetDebugManager()->SetOutputWindow(swapDesc.OutputWindow);
|
||||
}
|
||||
}
|
||||
|
||||
if(swap != m_SwapChain || m_SwapChain == NULL)
|
||||
if(!activeWindow)
|
||||
return S_OK;
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC swapDesc = {0};
|
||||
m_SwapChain->GetDesc(&swapDesc);
|
||||
RenderDoc::Inst().SetCurrentDriver(RDC_D3D11);
|
||||
|
||||
// kill any current capture that isn't application defined
|
||||
if(m_State == WRITING_CAPFRAME && !m_AppControlledCapture)
|
||||
EndFrameCapture(swapDesc.OutputWindow);
|
||||
EndFrameCapture(this, swapdesc.OutputWindow);
|
||||
|
||||
if(RenderDoc::Inst().ShouldTriggerCapture(m_FrameCounter) && m_State == WRITING_IDLE)
|
||||
{
|
||||
StartFrameCapture(swapDesc.OutputWindow);
|
||||
StartFrameCapture(this, swapdesc.OutputWindow);
|
||||
|
||||
m_AppControlledCapture = false;
|
||||
}
|
||||
|
||||
@@ -238,7 +238,6 @@ private:
|
||||
|
||||
static WrappedID3D11Device *m_pCurrentWrappedDevice;
|
||||
|
||||
IDXGISwapChain *m_SwapChain;
|
||||
map<IDXGISwapChain*, ID3D11RenderTargetView*> m_SwapChains;
|
||||
|
||||
uint32_t m_FrameCounter;
|
||||
@@ -300,9 +299,8 @@ public:
|
||||
|
||||
void Serialise_CaptureScope(uint64_t offset);
|
||||
|
||||
void StartFrameCapture(void *wnd);
|
||||
void SetActiveWindow(void *wnd);
|
||||
bool EndFrameCapture(void *wnd);
|
||||
void StartFrameCapture(void *dev, void *wnd);
|
||||
bool EndFrameCapture(void *dev, void *wnd);
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// log replaying
|
||||
|
||||
@@ -271,16 +271,12 @@ WrappedIDXGISwapChain2::WrappedIDXGISwapChain2(IDXGISwapChain* real, HWND wnd, W
|
||||
}
|
||||
}
|
||||
|
||||
if(m_Wnd) RenderDoc::Inst().AddFrameCapturer(m_Wnd, m_pDevice);
|
||||
|
||||
SAFE_ADDREF(m_pDevice);
|
||||
}
|
||||
|
||||
WrappedIDXGISwapChain2::~WrappedIDXGISwapChain2()
|
||||
{
|
||||
m_pDevice->ReleaseSwapchainResources(this);
|
||||
|
||||
if(m_Wnd) RenderDoc::Inst().RemoveFrameCapturer(m_Wnd);
|
||||
|
||||
for(int i=0; i < MAX_NUM_BACKBUFFERS; i++)
|
||||
{
|
||||
|
||||
+319
-190
@@ -673,17 +673,19 @@ WrappedOpenGL::WrappedOpenGL(const char *logfile, const GLHookSet &funcs)
|
||||
|
||||
m_FrameTimer.Restart();
|
||||
|
||||
m_AppControlledCapture = false;
|
||||
|
||||
m_TotalTime = m_AvgFrametime = m_MinFrametime = m_MaxFrametime = 0.0;
|
||||
|
||||
m_CurFileSize = 0;
|
||||
|
||||
m_RealDebugFunc = NULL;
|
||||
m_RealDebugFuncParam = NULL;
|
||||
|
||||
|
||||
m_DrawcallStack.push_back(&m_ParentDrawcall);
|
||||
|
||||
m_CurEventID = 0;
|
||||
m_CurDrawcallID = 0;
|
||||
m_CurEventID = 0;
|
||||
m_CurDrawcallID = 0;
|
||||
m_FirstEventID = 0;
|
||||
m_LastEventID = ~0U;
|
||||
|
||||
@@ -752,6 +754,8 @@ 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
|
||||
{
|
||||
@@ -899,6 +903,8 @@ 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);
|
||||
@@ -967,12 +973,32 @@ void WrappedOpenGL::DeleteContext(void *contextHandle)
|
||||
m_ContextData.erase(contextHandle);
|
||||
}
|
||||
|
||||
void WrappedOpenGL::ContextData::UnassociateWindow(void *wndHandle)
|
||||
{
|
||||
auto it = windows.find(wndHandle);
|
||||
if(it != windows.end())
|
||||
{
|
||||
windows.erase(wndHandle);
|
||||
RenderDoc::Inst().RemoveFrameCapturer(ctx, wndHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void WrappedOpenGL::ContextData::AssociateWindow(WrappedOpenGL *gl, void *wndHandle)
|
||||
{
|
||||
auto it = windows.find(wndHandle);
|
||||
if(it == windows.end())
|
||||
RenderDoc::Inst().AddFrameCapturer(ctx, wndHandle, gl);
|
||||
|
||||
windows[wndHandle] = Timing::GetUnixTimestamp();
|
||||
}
|
||||
|
||||
void WrappedOpenGL::CreateContext(GLWindowingData winData, void *shareContext, GLInitParams initParams, bool core, bool attribsCreate)
|
||||
{
|
||||
// TODO: support multiple GL contexts more explicitly
|
||||
m_InitParams = initParams;
|
||||
|
||||
ContextData &ctxdata = m_ContextData[winData.ctx];
|
||||
ctxdata.ctx = winData.ctx;
|
||||
ctxdata.isCore = core;
|
||||
ctxdata.attribsCreate = attribsCreate;
|
||||
}
|
||||
@@ -1920,15 +1946,54 @@ void WrappedOpenGL::FreeTargetResource(ResourceId id)
|
||||
}
|
||||
}
|
||||
|
||||
void WrappedOpenGL::Present(void *windowHandle)
|
||||
void WrappedOpenGL::SwapBuffers(void *windowHandle)
|
||||
{
|
||||
RenderDoc::Inst().SetCurrentDriver(RDC_OpenGL);
|
||||
|
||||
if(m_State == WRITING_IDLE)
|
||||
RenderDoc::Inst().Tick();
|
||||
|
||||
m_FrameCounter++; // first present becomes frame #1, this function is at the end of the frame
|
||||
|
||||
ContextData &ctxdata = GetCtxData();
|
||||
|
||||
// we only handle context-window associations here as it's too common to
|
||||
// create invisible helper windows while creating contexts, that then
|
||||
// become the default window.
|
||||
// Since we only capture windows that do SwapBuffers (i.e. if you're doing
|
||||
// headless rendering then you must capture via the API anyway), this
|
||||
// isn't a big problem.
|
||||
//
|
||||
// Also we only set up associations for capturable windows.
|
||||
if(ctxdata.Modern())
|
||||
{
|
||||
for(auto it=m_ContextData.begin(); it != m_ContextData.end(); ++it)
|
||||
if(it->first != ctxdata.ctx)
|
||||
it->second.UnassociateWindow(windowHandle);
|
||||
|
||||
ctxdata.AssociateWindow(this, windowHandle);
|
||||
}
|
||||
|
||||
bool activeWindow = RenderDoc::Inst().IsActiveWindow(ctxdata.ctx, windowHandle);
|
||||
|
||||
// look at previous associations and decay any that are too old
|
||||
uint64_t ref = Timing::GetUnixTimestamp() - 5; // 5 seconds
|
||||
|
||||
for(auto cit=m_ContextData.begin(); cit != m_ContextData.end(); ++cit)
|
||||
{
|
||||
for(auto wit=cit->second.windows.begin(); wit != cit->second.windows.end(); )
|
||||
{
|
||||
if(wit->second < ref)
|
||||
{
|
||||
auto remove = wit;
|
||||
++wit;
|
||||
cit->second.windows.erase(remove);
|
||||
}
|
||||
else
|
||||
{
|
||||
++wit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(m_State == WRITING_IDLE)
|
||||
{
|
||||
m_FrameTimes.push_back(m_FrameTimer.GetMilliseconds());
|
||||
@@ -1960,15 +2025,13 @@ void WrappedOpenGL::Present(void *windowHandle)
|
||||
|
||||
uint32_t overlay = RenderDoc::Inst().GetOverlayBits();
|
||||
|
||||
if((overlay & eOverlay_Enabled) && m_Real.glGetIntegerv && m_Real.glReadBuffer && m_Real.glBindFramebuffer && m_Real.glBindBuffer && m_Real.glReadPixels)
|
||||
if(overlay & eOverlay_Enabled)
|
||||
{
|
||||
RenderTextState textState;
|
||||
|
||||
ContextData &ctxdata = GetCtxData();
|
||||
|
||||
textState.Push(m_Real, ctxdata.Modern());
|
||||
|
||||
// TODO: handle selecting active window amongst many
|
||||
if(activeWindow)
|
||||
{
|
||||
vector<KeyButton> keys = RenderDoc::Inst().GetCaptureKeys();
|
||||
|
||||
@@ -2046,6 +2109,38 @@ void WrappedOpenGL::Present(void *windowHandle)
|
||||
y += 1.0f;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
vector<KeyButton> keys = RenderDoc::Inst().GetFocusKeys();
|
||||
|
||||
string str = "OpenGL. Inactive window.";
|
||||
|
||||
if(ctxdata.Modern())
|
||||
{
|
||||
for(size_t i=0; i < keys.size(); i++)
|
||||
{
|
||||
if(i == 0)
|
||||
str += " ";
|
||||
else
|
||||
str += ", ";
|
||||
|
||||
str += ToStr::Get(keys[i]);
|
||||
}
|
||||
|
||||
if(!keys.empty())
|
||||
str += " to cycle between windows.";
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!ctxdata.attribsCreate)
|
||||
{
|
||||
str += "\nContext not created via CreateContextAttribs. Capturing disabled.\n";
|
||||
}
|
||||
str += "Only OpenGL 3.2+ contexts are supported.";
|
||||
}
|
||||
|
||||
RenderOverlayText(0.0f, 0.0f, str.c_str());
|
||||
}
|
||||
|
||||
textState.Pop(m_Real, ctxdata.Modern());
|
||||
|
||||
@@ -2060,195 +2155,229 @@ void WrappedOpenGL::Present(void *windowHandle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// kill any current capture
|
||||
if(m_State == WRITING_CAPFRAME)
|
||||
{
|
||||
//if(HasSuccessfulCapture())
|
||||
{
|
||||
RDCLOG("Finished capture, Frame %u", m_FrameCounter);
|
||||
|
||||
EndCaptureFrame();
|
||||
FinishCapture();
|
||||
|
||||
const uint32_t maxSize = 1024;
|
||||
|
||||
byte *thpixels = NULL;
|
||||
uint32_t thwidth = 0;
|
||||
uint32_t thheight = 0;
|
||||
|
||||
if(m_Real.glGetIntegerv && m_Real.glReadBuffer && m_Real.glBindFramebuffer && m_Real.glBindBuffer && m_Real.glReadPixels)
|
||||
{
|
||||
RDCGLenum prevReadBuf = eGL_BACK;
|
||||
GLint prevBuf = 0;
|
||||
GLint packBufBind = 0;
|
||||
GLint prevPackRowLen = 0;
|
||||
GLint prevPackSkipRows = 0;
|
||||
GLint prevPackSkipPixels = 0;
|
||||
GLint prevPackAlignment = 0;
|
||||
m_Real.glGetIntegerv(eGL_READ_BUFFER, (GLint *)&prevReadBuf);
|
||||
m_Real.glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, &prevBuf);
|
||||
m_Real.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, &packBufBind);
|
||||
m_Real.glGetIntegerv(eGL_PACK_ROW_LENGTH, &prevPackRowLen);
|
||||
m_Real.glGetIntegerv(eGL_PACK_SKIP_ROWS, &prevPackSkipRows);
|
||||
m_Real.glGetIntegerv(eGL_PACK_SKIP_PIXELS, &prevPackSkipPixels);
|
||||
m_Real.glGetIntegerv(eGL_PACK_ALIGNMENT, &prevPackAlignment);
|
||||
|
||||
m_Real.glBindFramebuffer(eGL_READ_FRAMEBUFFER, 0);
|
||||
m_Real.glReadBuffer(eGL_BACK);
|
||||
m_Real.glBindBuffer(eGL_PIXEL_PACK_BUFFER, 0);
|
||||
m_Real.glPixelStorei(eGL_PACK_ROW_LENGTH, 0);
|
||||
m_Real.glPixelStorei(eGL_PACK_SKIP_ROWS, 0);
|
||||
m_Real.glPixelStorei(eGL_PACK_SKIP_PIXELS, 0);
|
||||
m_Real.glPixelStorei(eGL_PACK_ALIGNMENT, 1);
|
||||
|
||||
thwidth = m_InitParams.width;
|
||||
thheight = m_InitParams.height;
|
||||
|
||||
thpixels = new byte[thwidth*thheight*3];
|
||||
|
||||
m_Real.glReadPixels(0, 0, thwidth, thheight, eGL_RGB, eGL_UNSIGNED_BYTE, thpixels);
|
||||
|
||||
for(uint32_t y=0; y <= thheight/2; y++)
|
||||
{
|
||||
for(uint32_t x=0; x < thwidth; x++)
|
||||
{
|
||||
byte save[3];
|
||||
save[0] = thpixels[y*(thwidth*3) + x*3 + 0];
|
||||
save[1] = thpixels[y*(thwidth*3) + x*3 + 1];
|
||||
save[2] = thpixels[y*(thwidth*3) + x*3 + 2];
|
||||
|
||||
thpixels[y*(thwidth*3) + x*3 + 0] = thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 0];
|
||||
thpixels[y*(thwidth*3) + x*3 + 1] = thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 1];
|
||||
thpixels[y*(thwidth*3) + x*3 + 2] = thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 2];
|
||||
|
||||
thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 0] = save[0];
|
||||
thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 1] = save[1];
|
||||
thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 2] = save[2];
|
||||
}
|
||||
}
|
||||
|
||||
m_Real.glBindBuffer(eGL_PIXEL_PACK_BUFFER, packBufBind);
|
||||
m_Real.glBindFramebuffer(eGL_READ_FRAMEBUFFER, prevBuf);
|
||||
m_Real.glReadBuffer(prevReadBuf);
|
||||
m_Real.glPixelStorei(eGL_PACK_ROW_LENGTH, prevPackRowLen);
|
||||
m_Real.glPixelStorei(eGL_PACK_SKIP_ROWS, prevPackSkipRows);
|
||||
m_Real.glPixelStorei(eGL_PACK_SKIP_PIXELS, prevPackSkipPixels);
|
||||
m_Real.glPixelStorei(eGL_PACK_ALIGNMENT, prevPackAlignment);
|
||||
}
|
||||
|
||||
byte *jpgbuf = NULL;
|
||||
int len = thwidth*thheight;
|
||||
|
||||
if(len > 0)
|
||||
{
|
||||
jpgbuf = new byte[len];
|
||||
|
||||
jpge::params p;
|
||||
|
||||
p.m_quality = 40;
|
||||
|
||||
bool success = jpge::compress_image_to_jpeg_file_in_memory(jpgbuf, len, thwidth, thheight, 3, thpixels, p);
|
||||
|
||||
if(!success)
|
||||
{
|
||||
RDCERR("Failed to compress to jpg");
|
||||
SAFE_DELETE_ARRAY(jpgbuf);
|
||||
thwidth = 0;
|
||||
thheight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Serialiser *m_pFileSerialiser = RenderDoc::Inst().OpenWriteSerialiser(m_FrameCounter, &m_InitParams, jpgbuf, len, thwidth, thheight);
|
||||
|
||||
{
|
||||
SCOPED_SERIALISE_CONTEXT(DEVICE_INIT);
|
||||
|
||||
SERIALISE_ELEMENT(ResourceId, immContextId, m_ContextResourceID);
|
||||
SERIALISE_ELEMENT(ResourceId, vaoId, m_FakeVAOID);
|
||||
|
||||
m_pFileSerialiser->Insert(scope.Get(true));
|
||||
}
|
||||
|
||||
RDCDEBUG("Inserting Resource Serialisers");
|
||||
|
||||
GetResourceManager()->InsertReferencedChunks(m_pFileSerialiser);
|
||||
|
||||
GetResourceManager()->InsertInitialContentsChunks(m_pFileSerialiser);
|
||||
|
||||
RDCDEBUG("Creating Capture Scope");
|
||||
|
||||
{
|
||||
SCOPED_SERIALISE_CONTEXT(CAPTURE_SCOPE);
|
||||
|
||||
Serialise_CaptureScope(0);
|
||||
|
||||
m_pFileSerialiser->Insert(scope.Get(true));
|
||||
}
|
||||
|
||||
{
|
||||
RDCDEBUG("Getting Resource Record");
|
||||
|
||||
GLResourceRecord *record = m_ResourceManager->GetResourceRecord(m_ContextResourceID);
|
||||
|
||||
RDCDEBUG("Accumulating context resource list");
|
||||
|
||||
map<int32_t, Chunk *> recordlist;
|
||||
record->Insert(recordlist);
|
||||
|
||||
RDCDEBUG("Flushing %u records to file serialiser", (uint32_t)recordlist.size());
|
||||
|
||||
for(auto it = recordlist.begin(); it != recordlist.end(); ++it)
|
||||
m_pFileSerialiser->Insert(it->second);
|
||||
|
||||
RDCDEBUG("Done");
|
||||
}
|
||||
|
||||
m_CurFileSize += m_pFileSerialiser->FlushToDisk();
|
||||
|
||||
RenderDoc::Inst().SuccessfullyWrittenLog();
|
||||
|
||||
SAFE_DELETE(m_pFileSerialiser);
|
||||
|
||||
m_State = WRITING_IDLE;
|
||||
|
||||
GetResourceManager()->MarkUnwrittenResources();
|
||||
|
||||
GetResourceManager()->ClearReferencedResources();
|
||||
}
|
||||
}
|
||||
|
||||
if(!activeWindow)
|
||||
return;
|
||||
|
||||
RenderDoc::Inst().SetCurrentDriver(RDC_OpenGL);
|
||||
|
||||
// only allow capturing on 'modern' created contexts
|
||||
if(GetCtxData().Modern() && RenderDoc::Inst().ShouldTriggerCapture(m_FrameCounter) && m_State == WRITING_IDLE && m_FrameRecord.empty())
|
||||
if(ctxdata.Legacy())
|
||||
return;
|
||||
|
||||
// kill any current capture that isn't application defined
|
||||
if(m_State == WRITING_CAPFRAME && !m_AppControlledCapture)
|
||||
EndFrameCapture(this, windowHandle);
|
||||
|
||||
// for now, only allow one captured frame at all
|
||||
if(!m_FrameRecord.empty())
|
||||
return;
|
||||
|
||||
if(RenderDoc::Inst().ShouldTriggerCapture(m_FrameCounter) && m_State == WRITING_IDLE)
|
||||
{
|
||||
m_State = WRITING_CAPFRAME;
|
||||
StartFrameCapture(this, windowHandle);
|
||||
|
||||
GLWindowingData &prevctx = m_ActiveContexts[Threading::GetCurrentID()];
|
||||
m_AppControlledCapture = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool switchedContext = false;
|
||||
if(prevctx.ctx == NULL)
|
||||
void WrappedOpenGL::StartFrameCapture(void *dev, void *wnd)
|
||||
{
|
||||
m_State = WRITING_CAPFRAME;
|
||||
|
||||
m_AppControlledCapture = true;
|
||||
|
||||
GLWindowingData &prevctx = m_ActiveContexts[Threading::GetCurrentID()];
|
||||
|
||||
bool switchedContext = false;
|
||||
if(prevctx.ctx == NULL)
|
||||
{
|
||||
MakeContextCurrent(m_DefaultContexts[Threading::GetCurrentID()]);
|
||||
switchedContext = true;
|
||||
}
|
||||
|
||||
FetchFrameRecord record;
|
||||
record.frameInfo.frameNumber = m_FrameCounter+1;
|
||||
record.frameInfo.captureTime = Timing::GetUnixTimestamp();
|
||||
m_FrameRecord.push_back(record);
|
||||
|
||||
GetResourceManager()->ClearReferencedResources();
|
||||
|
||||
GetResourceManager()->MarkResourceFrameReferenced(m_DeviceResourceID, eFrameRef_Write);
|
||||
GetResourceManager()->PrepareInitialContents();
|
||||
|
||||
AttemptCapture();
|
||||
BeginCaptureFrame();
|
||||
|
||||
if(switchedContext)
|
||||
MakeContextCurrent(prevctx);
|
||||
|
||||
RDCLOG("Starting capture, frame %u", m_FrameCounter);
|
||||
}
|
||||
|
||||
bool WrappedOpenGL::EndFrameCapture(void *dev, void *wnd)
|
||||
{
|
||||
if(m_State != WRITING_CAPFRAME) return true;
|
||||
|
||||
CaptureFailReason reason = CaptureSucceeded;
|
||||
|
||||
//if(HasSuccessfulCapture(reason))
|
||||
{
|
||||
RDCLOG("Finished capture, Frame %u", m_FrameCounter);
|
||||
|
||||
ContextEndFrame();
|
||||
FinishCapture();
|
||||
|
||||
const uint32_t maxSize = 1024;
|
||||
|
||||
byte *thpixels = NULL;
|
||||
uint32_t thwidth = 0;
|
||||
uint32_t thheight = 0;
|
||||
|
||||
if(m_Real.glGetIntegerv && m_Real.glReadBuffer && m_Real.glBindFramebuffer && m_Real.glBindBuffer && m_Real.glReadPixels)
|
||||
{
|
||||
MakeContextCurrent(m_DefaultContexts[Threading::GetCurrentID()]);
|
||||
switchedContext = true;
|
||||
RDCGLenum prevReadBuf = eGL_BACK;
|
||||
GLint prevBuf = 0;
|
||||
GLint packBufBind = 0;
|
||||
GLint prevPackRowLen = 0;
|
||||
GLint prevPackSkipRows = 0;
|
||||
GLint prevPackSkipPixels = 0;
|
||||
GLint prevPackAlignment = 0;
|
||||
m_Real.glGetIntegerv(eGL_READ_BUFFER, (GLint *)&prevReadBuf);
|
||||
m_Real.glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, &prevBuf);
|
||||
m_Real.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, &packBufBind);
|
||||
m_Real.glGetIntegerv(eGL_PACK_ROW_LENGTH, &prevPackRowLen);
|
||||
m_Real.glGetIntegerv(eGL_PACK_SKIP_ROWS, &prevPackSkipRows);
|
||||
m_Real.glGetIntegerv(eGL_PACK_SKIP_PIXELS, &prevPackSkipPixels);
|
||||
m_Real.glGetIntegerv(eGL_PACK_ALIGNMENT, &prevPackAlignment);
|
||||
|
||||
m_Real.glBindFramebuffer(eGL_READ_FRAMEBUFFER, 0);
|
||||
m_Real.glReadBuffer(eGL_BACK);
|
||||
m_Real.glBindBuffer(eGL_PIXEL_PACK_BUFFER, 0);
|
||||
m_Real.glPixelStorei(eGL_PACK_ROW_LENGTH, 0);
|
||||
m_Real.glPixelStorei(eGL_PACK_SKIP_ROWS, 0);
|
||||
m_Real.glPixelStorei(eGL_PACK_SKIP_PIXELS, 0);
|
||||
m_Real.glPixelStorei(eGL_PACK_ALIGNMENT, 1);
|
||||
|
||||
thwidth = m_InitParams.width;
|
||||
thheight = m_InitParams.height;
|
||||
|
||||
thpixels = new byte[thwidth*thheight*3];
|
||||
|
||||
m_Real.glReadPixels(0, 0, thwidth, thheight, eGL_RGB, eGL_UNSIGNED_BYTE, thpixels);
|
||||
|
||||
for(uint32_t y=0; y <= thheight/2; y++)
|
||||
{
|
||||
for(uint32_t x=0; x < thwidth; x++)
|
||||
{
|
||||
byte save[3];
|
||||
save[0] = thpixels[y*(thwidth*3) + x*3 + 0];
|
||||
save[1] = thpixels[y*(thwidth*3) + x*3 + 1];
|
||||
save[2] = thpixels[y*(thwidth*3) + x*3 + 2];
|
||||
|
||||
thpixels[y*(thwidth*3) + x*3 + 0] = thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 0];
|
||||
thpixels[y*(thwidth*3) + x*3 + 1] = thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 1];
|
||||
thpixels[y*(thwidth*3) + x*3 + 2] = thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 2];
|
||||
|
||||
thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 0] = save[0];
|
||||
thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 1] = save[1];
|
||||
thpixels[(thheight-1-y)*(thwidth*3) + x*3 + 2] = save[2];
|
||||
}
|
||||
}
|
||||
|
||||
m_Real.glBindBuffer(eGL_PIXEL_PACK_BUFFER, packBufBind);
|
||||
m_Real.glBindFramebuffer(eGL_READ_FRAMEBUFFER, prevBuf);
|
||||
m_Real.glReadBuffer(prevReadBuf);
|
||||
m_Real.glPixelStorei(eGL_PACK_ROW_LENGTH, prevPackRowLen);
|
||||
m_Real.glPixelStorei(eGL_PACK_SKIP_ROWS, prevPackSkipRows);
|
||||
m_Real.glPixelStorei(eGL_PACK_SKIP_PIXELS, prevPackSkipPixels);
|
||||
m_Real.glPixelStorei(eGL_PACK_ALIGNMENT, prevPackAlignment);
|
||||
}
|
||||
|
||||
FetchFrameRecord record;
|
||||
record.frameInfo.frameNumber = m_FrameCounter+1;
|
||||
record.frameInfo.captureTime = Timing::GetUnixTimestamp();
|
||||
m_FrameRecord.push_back(record);
|
||||
byte *jpgbuf = NULL;
|
||||
int len = thwidth*thheight;
|
||||
|
||||
if(len > 0)
|
||||
{
|
||||
jpgbuf = new byte[len];
|
||||
|
||||
jpge::params p;
|
||||
|
||||
p.m_quality = 40;
|
||||
|
||||
bool success = jpge::compress_image_to_jpeg_file_in_memory(jpgbuf, len, thwidth, thheight, 3, thpixels, p);
|
||||
|
||||
if(!success)
|
||||
{
|
||||
RDCERR("Failed to compress to jpg");
|
||||
SAFE_DELETE_ARRAY(jpgbuf);
|
||||
thwidth = 0;
|
||||
thheight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Serialiser *m_pFileSerialiser = RenderDoc::Inst().OpenWriteSerialiser(m_FrameCounter, &m_InitParams, jpgbuf, len, thwidth, thheight);
|
||||
|
||||
{
|
||||
SCOPED_SERIALISE_CONTEXT(DEVICE_INIT);
|
||||
|
||||
SERIALISE_ELEMENT(ResourceId, immContextId, m_ContextResourceID);
|
||||
SERIALISE_ELEMENT(ResourceId, vaoId, m_FakeVAOID);
|
||||
|
||||
m_pFileSerialiser->Insert(scope.Get(true));
|
||||
}
|
||||
|
||||
RDCDEBUG("Inserting Resource Serialisers");
|
||||
|
||||
GetResourceManager()->InsertReferencedChunks(m_pFileSerialiser);
|
||||
|
||||
GetResourceManager()->InsertInitialContentsChunks(m_pFileSerialiser);
|
||||
|
||||
RDCDEBUG("Creating Capture Scope");
|
||||
|
||||
{
|
||||
SCOPED_SERIALISE_CONTEXT(CAPTURE_SCOPE);
|
||||
|
||||
Serialise_CaptureScope(0);
|
||||
|
||||
m_pFileSerialiser->Insert(scope.Get(true));
|
||||
}
|
||||
|
||||
{
|
||||
RDCDEBUG("Getting Resource Record");
|
||||
|
||||
GLResourceRecord *record = m_ResourceManager->GetResourceRecord(m_ContextResourceID);
|
||||
|
||||
RDCDEBUG("Accumulating context resource list");
|
||||
|
||||
map<int32_t, Chunk *> recordlist;
|
||||
record->Insert(recordlist);
|
||||
|
||||
RDCDEBUG("Flushing %u records to file serialiser", (uint32_t)recordlist.size());
|
||||
|
||||
for(auto it = recordlist.begin(); it != recordlist.end(); ++it)
|
||||
m_pFileSerialiser->Insert(it->second);
|
||||
|
||||
RDCDEBUG("Done");
|
||||
}
|
||||
|
||||
m_CurFileSize += m_pFileSerialiser->FlushToDisk();
|
||||
|
||||
RenderDoc::Inst().SuccessfullyWrittenLog();
|
||||
|
||||
SAFE_DELETE(m_pFileSerialiser);
|
||||
|
||||
m_State = WRITING_IDLE;
|
||||
|
||||
GetResourceManager()->MarkUnwrittenResources();
|
||||
|
||||
GetResourceManager()->ClearReferencedResources();
|
||||
|
||||
GetResourceManager()->MarkResourceFrameReferenced(m_DeviceResourceID, eFrameRef_Write);
|
||||
GetResourceManager()->PrepareInitialContents();
|
||||
|
||||
AttemptCapture();
|
||||
BeginCaptureFrame();
|
||||
|
||||
if(switchedContext)
|
||||
MakeContextCurrent(prevctx);
|
||||
|
||||
RDCLOG("Starting capture, frame %u", m_FrameCounter);
|
||||
return true;
|
||||
}
|
||||
//else
|
||||
{
|
||||
// failed to capture
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2273,7 +2402,7 @@ void WrappedOpenGL::Serialise_CaptureScope(uint64_t offset)
|
||||
}
|
||||
}
|
||||
|
||||
void WrappedOpenGL::EndCaptureFrame()
|
||||
void WrappedOpenGL::ContextEndFrame()
|
||||
{
|
||||
SCOPED_SERIALISE_CONTEXT(CONTEXT_CAPTURE_FOOTER);
|
||||
|
||||
@@ -2314,7 +2443,7 @@ void WrappedOpenGL::AttemptCapture()
|
||||
m_DebugMessages.clear();
|
||||
|
||||
{
|
||||
RDCDEBUG("Immediate Context %llu Attempting capture", GetContextResourceID());
|
||||
RDCDEBUG("GL Context %llu Attempting capture", GetContextResourceID());
|
||||
|
||||
//m_SuccessfulCapture = true;
|
||||
|
||||
|
||||
@@ -61,6 +61,12 @@ struct GLInitParams : public RDCInitParams
|
||||
uint32_t SerialiseVersion;
|
||||
};
|
||||
|
||||
enum CaptureFailReason
|
||||
{
|
||||
CaptureSucceeded = 0,
|
||||
CaptureFailed_UncappedUnmap,
|
||||
};
|
||||
|
||||
struct DrawcallTreeNode
|
||||
{
|
||||
DrawcallTreeNode() {}
|
||||
@@ -93,7 +99,7 @@ struct Replacement
|
||||
GLResource res;
|
||||
};
|
||||
|
||||
class WrappedOpenGL
|
||||
class WrappedOpenGL : public IFrameCapturer
|
||||
{
|
||||
private:
|
||||
const GLHookSet &m_Real;
|
||||
@@ -124,6 +130,7 @@ class WrappedOpenGL
|
||||
// internals
|
||||
Serialiser *m_pSerialiser;
|
||||
LogState m_State;
|
||||
bool m_AppControlledCapture;
|
||||
|
||||
GLReplay m_Replay;
|
||||
|
||||
@@ -311,8 +318,8 @@ class WrappedOpenGL
|
||||
bool Serialise_BeginCaptureFrame(bool applyInitialState);
|
||||
void BeginCaptureFrame();
|
||||
void FinishCapture();
|
||||
void EndCaptureFrame();
|
||||
|
||||
void ContextEndFrame();
|
||||
|
||||
struct ContextData
|
||||
{
|
||||
ContextData()
|
||||
@@ -333,6 +340,8 @@ class WrappedOpenGL
|
||||
m_ProgramPipeline = m_Program = 0;
|
||||
}
|
||||
|
||||
void *ctx;
|
||||
|
||||
bool built;
|
||||
bool ready;
|
||||
|
||||
@@ -340,6 +349,18 @@ class WrappedOpenGL
|
||||
bool attribsCreate;
|
||||
bool isCore;
|
||||
|
||||
// map from window handle void* to uint64_t unix timestamp with
|
||||
// the last time a window was seen/associated with this context.
|
||||
// Decays after a few seconds since there's no good explicit
|
||||
// 'remove' type call for GL, only wglCreateContext/wglMakeCurrent
|
||||
map<void *, uint64_t> windows;
|
||||
|
||||
// a window is only associated with one context at once, so any
|
||||
// time we associate a window, it broadcasts to all other
|
||||
// contexts to let them know to remove it
|
||||
void UnassociateWindow(void *wndHandle);
|
||||
void AssociateWindow(WrappedOpenGL *gl, void *wndHandle);
|
||||
|
||||
bool Legacy() { return !attribsCreate || version < 32; }
|
||||
bool Modern() { return !Legacy(); }
|
||||
|
||||
@@ -445,7 +466,15 @@ class WrappedOpenGL
|
||||
void DeleteContext(void *contextHandle);
|
||||
void ActivateContext(GLWindowingData winData);
|
||||
void WindowSize(void *windowHandle, uint32_t w, uint32_t h);
|
||||
void Present(void *windowHandle);
|
||||
void SwapBuffers(void *windowHandle);
|
||||
|
||||
void StartFrameCapture();
|
||||
|
||||
void EndFrameCapture();
|
||||
|
||||
|
||||
void StartFrameCapture(void *dev, void *wnd);
|
||||
bool EndFrameCapture(void *dev, void *wnd);
|
||||
|
||||
IMPLEMENT_FUNCTION_SERIALISED(void, glBindTexture(GLenum target, GLuint texture));
|
||||
IMPLEMENT_FUNCTION_SERIALISED(void, glBindTextures(GLuint first, GLsizei count, const GLuint *textures));
|
||||
|
||||
@@ -202,7 +202,7 @@ void WrappedOpenGL::glInsertEventMarkerEXT(GLsizei length, const GLchar *marker)
|
||||
|
||||
void WrappedOpenGL::glFrameTerminatorGREMEDY()
|
||||
{
|
||||
Present(NULL);
|
||||
SwapBuffers(NULL);
|
||||
}
|
||||
|
||||
void WrappedOpenGL::glStringMarkerGREMEDY(GLsizei len, const void *string)
|
||||
|
||||
@@ -518,7 +518,7 @@ class OpenGLHook : LibraryHook
|
||||
|
||||
glhooks.GetDriver()->WindowSize(w, r.right-r.left, r.bottom-r.top);
|
||||
|
||||
glhooks.GetDriver()->Present(w);
|
||||
glhooks.GetDriver()->SwapBuffers(w);
|
||||
|
||||
return glhooks.SwapBuffers_hook()(dc);
|
||||
}
|
||||
|
||||
@@ -246,9 +246,9 @@ uint32_t RENDERDOC_CC RENDERDOC_InjectIntoProcess(uint32_t pid, const char *logf
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API
|
||||
void RENDERDOC_CC RENDERDOC_SetActiveWindow(void *wndHandle)
|
||||
void RENDERDOC_CC RENDERDOC_SetActiveWindow(void *device, void *wndHandle)
|
||||
{
|
||||
RenderDoc::Inst().SetActiveWindow(wndHandle);
|
||||
RenderDoc::Inst().SetActiveWindow(device, wndHandle);
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API
|
||||
@@ -258,15 +258,15 @@ void RENDERDOC_CC RENDERDOC_TriggerCapture()
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API
|
||||
void RENDERDOC_CC RENDERDOC_StartFrameCapture(void *wndHandle)
|
||||
void RENDERDOC_CC RENDERDOC_StartFrameCapture(void *device, void *wndHandle)
|
||||
{
|
||||
RenderDoc::Inst().StartFrameCapture(wndHandle);
|
||||
RenderDoc::Inst().StartFrameCapture(device, wndHandle);
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API
|
||||
bool32 RENDERDOC_CC RENDERDOC_EndFrameCapture(void *wndHandle)
|
||||
bool32 RENDERDOC_CC RENDERDOC_EndFrameCapture(void *device, void *wndHandle)
|
||||
{
|
||||
return RenderDoc::Inst().EndFrameCapture(wndHandle);
|
||||
return RenderDoc::Inst().EndFrameCapture(device, wndHandle);
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API
|
||||
|
||||
Reference in New Issue
Block a user