diff --git a/renderdoc/driver/d3d11/d3d11_device.cpp b/renderdoc/driver/d3d11/d3d11_device.cpp index 38f2913fd..b4aa60fd2 100644 --- a/renderdoc/driver/d3d11/d3d11_device.cpp +++ b/renderdoc/driver/d3d11/d3d11_device.cpp @@ -903,7 +903,8 @@ bool WrappedID3D11Device::ProcessChunk(ReadSerialiser &ser, D3D11Chunk context) return true; } case D3D11Chunk::SetResourceName: return Serialise_SetResourceName(ser, 0x0, ""); - case D3D11Chunk::CreateSwapBuffer: return Serialise_WrapSwapchainBuffer(ser, 0x0, 0x0, 0, 0x0); + case D3D11Chunk::CreateSwapBuffer: + return Serialise_WrapSwapchainBuffer(ser, 0x0, DXGI_FORMAT_UNKNOWN, 0, 0x0); case D3D11Chunk::CreateTexture1D: return Serialise_CreateTexture1D(ser, 0x0, 0x0, 0x0); case D3D11Chunk::CreateTexture2D: return Serialise_CreateTexture2D(ser, 0x0, 0x0, 0x0); @@ -1254,7 +1255,7 @@ void WrappedID3D11Device::ReplayLog(uint32_t startEventID, uint32_t endEventID, D3D11MarkerRegion::Set("!!!!RenderDoc Internal: Done replay"); } -void WrappedID3D11Device::ReleaseSwapchainResources(WrappedIDXGISwapChain4 *swap, UINT QueueCount, +void WrappedID3D11Device::ReleaseSwapchainResources(IDXGISwapper *swapper, UINT QueueCount, IUnknown *const *ppPresentQueue, IUnknown **unwrappedQueues) { @@ -1267,9 +1268,9 @@ void WrappedID3D11Device::ReleaseSwapchainResources(WrappedIDXGISwapChain4 *swap unwrappedQueues[i] = ppPresentQueue[i]; } - for(int i = 0; i < swap->GetNumBackbuffers(); i++) + for(int i = 0; i < swapper->GetNumBackbuffers(); i++) { - WrappedID3D11Texture2D1 *wrapped11 = (WrappedID3D11Texture2D1 *)swap->GetBackbuffers()[i]; + WrappedID3D11Texture2D1 *wrapped11 = (WrappedID3D11Texture2D1 *)swapper->GetBackbuffers()[i]; if(wrapped11) { ResourceRange range(wrapped11); @@ -1292,16 +1293,16 @@ void WrappedID3D11Device::ReleaseSwapchainResources(WrappedIDXGISwapChain4 *swap wrapped11 = NULL; } - if(swap) + HWND wnd = swapper->GetHWND(); + + if(wnd) { - DXGI_SWAP_CHAIN_DESC desc = swap->GetDescWithHWND(); + Keyboard::RemoveInputWindow(wnd); - Keyboard::RemoveInputWindow(desc.OutputWindow); - - RenderDoc::Inst().RemoveFrameCapturer((ID3D11Device *)this, desc.OutputWindow); + RenderDoc::Inst().RemoveFrameCapturer((ID3D11Device *)this, wnd); } - auto it = m_SwapChains.find(swap); + auto it = m_SwapChains.find(swapper); if(it != m_SwapChains.end()) { SAFE_RELEASE(it->second); @@ -1310,9 +1311,8 @@ void WrappedID3D11Device::ReleaseSwapchainResources(WrappedIDXGISwapChain4 *swap } template -bool WrappedID3D11Device::Serialise_WrapSwapchainBuffer(SerialiserType &ser, - WrappedIDXGISwapChain4 *swap, - DXGI_SWAP_CHAIN_DESC *swapDesc, UINT Buffer, +bool WrappedID3D11Device::Serialise_WrapSwapchainBuffer(SerialiserType &ser, IDXGISwapper *swapper, + DXGI_FORMAT bufferFormat, UINT Buffer, IUnknown *realSurface) { WrappedID3D11Texture2D1 *pTex = (WrappedID3D11Texture2D1 *)realSurface; @@ -1367,9 +1367,8 @@ bool WrappedID3D11Device::Serialise_WrapSwapchainBuffer(SerialiserType &ser, return true; } -IUnknown *WrappedID3D11Device::WrapSwapchainBuffer(WrappedIDXGISwapChain4 *swap, - DXGI_SWAP_CHAIN_DESC *swapDesc, UINT buffer, - IUnknown *realSurface) +IUnknown *WrappedID3D11Device::WrapSwapchainBuffer(IDXGISwapper *swapper, DXGI_FORMAT bufferFormat, + UINT buffer, IUnknown *realSurface) { if(GetResourceManager()->HasWrapper((ID3D11DeviceChild *)realSurface)) { @@ -1415,7 +1414,7 @@ IUnknown *WrappedID3D11Device::WrapSwapchainBuffer(WrappedIDXGISwapChain4 *swap, SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateSwapBuffer); - Serialise_WrapSwapchainBuffer(ser, swap, swapDesc, buffer, pTex); + Serialise_WrapSwapchainBuffer(ser, swapper, bufferFormat, buffer, pTex); record->AddChunk(scope.Get()); } @@ -1428,16 +1427,16 @@ IUnknown *WrappedID3D11Device::WrapSwapchainBuffer(WrappedIDXGISwapChain4 *swap, if(FAILED(hr)) RDCERR("Couldn't create RTV for swapchain tex HRESULT: %s", ToStr(hr).c_str()); - m_SwapChains[swap] = rtv; + m_SwapChains[swapper] = rtv; } - if(swap) + HWND wnd = swapper->GetHWND(); + + if(wnd) { - DXGI_SWAP_CHAIN_DESC sdesc = swap->GetDescWithHWND(); + Keyboard::AddInputWindow(wnd); - Keyboard::AddInputWindow(sdesc.OutputWindow); - - RenderDoc::Inst().AddFrameCapturer((ID3D11Device *)this, sdesc.OutputWindow, this); + RenderDoc::Inst().AddFrameCapturer((ID3D11Device *)this, wnd, this); } return pTex; @@ -1531,22 +1530,20 @@ bool WrappedID3D11Device::EndFrameCapture(void *dev, void *wnd) CaptureFailReason reason; - WrappedIDXGISwapChain4 *swap = NULL; + IDXGISwapper *swapper = NULL; if(wnd) { for(auto it = m_SwapChains.begin(); it != m_SwapChains.end(); ++it) { - DXGI_SWAP_CHAIN_DESC swapDesc = it->first->GetDescWithHWND(); - - if(swapDesc.OutputWindow == wnd) + if(it->first->GetHWND() == wnd) { - swap = it->first; + swapper = it->first; break; } } - if(swap == NULL) + if(swapper == NULL) { RDCERR("Output window %p provided for frame capture corresponds with no known swap chain", wnd); return false; @@ -1581,9 +1578,9 @@ bool WrappedID3D11Device::EndFrameCapture(void *dev, void *wnd) const uint32_t maxSize = 2048; RenderDoc::FramePixels fp; - if(swap != NULL) + if(swapper != NULL) { - ID3D11RenderTargetView *rtv = m_SwapChains[swap]; + ID3D11RenderTargetView *rtv = m_SwapChains[swapper]; ID3D11Resource *res = NULL; @@ -1828,19 +1825,18 @@ bool WrappedID3D11Device::EndFrameCapture(void *dev, void *wnd) m_Failures++; - if((RenderDoc::Inst().GetOverlayBits() & eRENDERDOC_Overlay_Enabled) && swap != NULL) + if((RenderDoc::Inst().GetOverlayBits() & eRENDERDOC_Overlay_Enabled) && swapper) { D3D11RenderState old = *m_pImmediateContext->GetCurrentPipelineState(); - ID3D11RenderTargetView *rtv = m_SwapChains[swap]; + ID3D11RenderTargetView *rtv = m_SwapChains[swapper]; if(rtv) { m_pImmediateContext->GetReal()->OMSetRenderTargets(1, &rtv, NULL); - DXGI_SWAP_CHAIN_DESC swapDesc = swap->GetDescWithHWND(); - m_TextRenderer->SetOutputDimensions(swapDesc.BufferDesc.Width, swapDesc.BufferDesc.Height); - m_TextRenderer->SetOutputWindow(swapDesc.OutputWindow); + m_TextRenderer->SetOutputDimensions(swapper->GetWidth(), swapper->GetHeight()); + m_TextRenderer->SetOutputWindow(swapper->GetHWND()); m_TextRenderer->RenderText(0.0f, 0.0f, "Failed to capture frame %u: %s", m_FrameCounter, reasonString); @@ -2091,20 +2087,18 @@ void WrappedID3D11Device::UnlockForChunkRemoval() } } -void WrappedID3D11Device::FirstFrame(WrappedIDXGISwapChain4 *swapChain) +void WrappedID3D11Device::FirstFrame(IDXGISwapper *swapper) { - DXGI_SWAP_CHAIN_DESC swapdesc = swapChain->GetDescWithHWND(); - // if we have to capture the first frame, begin capturing immediately if(IsBackgroundCapturing(m_State) && RenderDoc::Inst().ShouldTriggerCapture(0)) { - RenderDoc::Inst().StartFrameCapture((ID3D11Device *)this, swapdesc.OutputWindow); + RenderDoc::Inst().StartFrameCapture((ID3D11Device *)this, swapper->GetHWND()); m_AppControlledCapture = false; } } -HRESULT WrappedID3D11Device::Present(WrappedIDXGISwapChain4 *swap, UINT SyncInterval, UINT Flags) +HRESULT WrappedID3D11Device::Present(IDXGISwapper *swapper, UINT SyncInterval, UINT Flags) { if((Flags & DXGI_PRESENT_TEST) != 0) return S_OK; @@ -2120,8 +2114,7 @@ HRESULT WrappedID3D11Device::Present(WrappedIDXGISwapChain4 *swap, UINT SyncInte m_pImmediateContext->BeginFrame(); - DXGI_SWAP_CHAIN_DESC swapdesc = swap->GetDescWithHWND(); - bool activeWindow = RenderDoc::Inst().IsActiveWindow((ID3D11Device *)this, swapdesc.OutputWindow); + bool activeWindow = RenderDoc::Inst().IsActiveWindow((ID3D11Device *)this, swapper->GetHWND()); if(IsBackgroundCapturing(m_State)) { @@ -2131,14 +2124,12 @@ HRESULT WrappedID3D11Device::Present(WrappedIDXGISwapChain4 *swap, UINT SyncInte if(overlay & eRENDERDOC_Overlay_Enabled) { - ID3D11RenderTargetView *rtv = m_SwapChains[swap]; + ID3D11RenderTargetView *rtv = m_SwapChains[swapper]; m_pImmediateContext->GetReal()->OMSetRenderTargets(1, &rtv, NULL); - DXGI_SWAP_CHAIN_DESC swapDesc = {0}; - swap->GetDesc(&swapDesc); - m_TextRenderer->SetOutputDimensions(swapDesc.BufferDesc.Width, swapDesc.BufferDesc.Height); - m_TextRenderer->SetOutputWindow(swapDesc.OutputWindow); + m_TextRenderer->SetOutputDimensions(swapper->GetWidth(), swapper->GetHeight()); + m_TextRenderer->SetOutputWindow(swapper->GetHWND()); int flags = activeWindow ? RenderDoc::eOverlay_ActiveWindow : 0; std::string overlayText = @@ -2175,12 +2166,12 @@ HRESULT WrappedID3D11Device::Present(WrappedIDXGISwapChain4 *swap, UINT SyncInte { m_pImmediateContext->Present(SyncInterval, Flags); - RenderDoc::Inst().EndFrameCapture((ID3D11Device *)this, swapdesc.OutputWindow); + RenderDoc::Inst().EndFrameCapture((ID3D11Device *)this, swapper->GetHWND()); } if(IsBackgroundCapturing(m_State) && RenderDoc::Inst().ShouldTriggerCapture(m_FrameCounter)) { - RenderDoc::Inst().StartFrameCapture((ID3D11Device *)this, swapdesc.OutputWindow); + RenderDoc::Inst().StartFrameCapture((ID3D11Device *)this, swapper->GetHWND()); m_AppControlledCapture = false; } diff --git a/renderdoc/driver/d3d11/d3d11_device.h b/renderdoc/driver/d3d11/d3d11_device.h index da0857633..905fcb2c6 100644 --- a/renderdoc/driver/d3d11/d3d11_device.h +++ b/renderdoc/driver/d3d11/d3d11_device.h @@ -371,7 +371,7 @@ private: static WrappedID3D11Device *m_pCurrentWrappedDevice; - std::map m_SwapChains; + std::map m_SwapChains; uint32_t m_FrameCounter; uint32_t m_FailedFrame; @@ -440,7 +440,7 @@ public: void UnlockForChunkRemoval(); SDFile &GetStructuredFile() { return *m_StructuredFile; } - void FirstFrame(WrappedIDXGISwapChain4 *swapChain); + void FirstFrame(IDXGISwapper *swapper); std::vector GetDebugMessages(); void AddDebugMessage(DebugMessage msg); @@ -519,8 +519,8 @@ public: const char *Path); // Swap Chain - IMPLEMENT_FUNCTION_SERIALISED(IUnknown *, WrapSwapchainBuffer, WrappedIDXGISwapChain4 *swap, - DXGI_SWAP_CHAIN_DESC *desc, UINT buffer, IUnknown *realSurface); + IMPLEMENT_FUNCTION_SERIALISED(IUnknown *, WrapSwapchainBuffer, IDXGISwapper *swapper, + DXGI_FORMAT bufferFormat, UINT buffer, IUnknown *realSurface); // this is defined as a macro so that we can re-use it to explicitly instantiate these functions as // templates in the wrapper definition file. @@ -536,11 +536,11 @@ public: SERIALISED_ID3D11DEVICE_FAKE_FUNCTIONS(); - HRESULT Present(WrappedIDXGISwapChain4 *swap, UINT SyncInterval, UINT Flags); + HRESULT Present(IDXGISwapper *swapper, UINT SyncInterval, UINT Flags); void NewSwapchainBuffer(IUnknown *backbuffer); - void ReleaseSwapchainResources(WrappedIDXGISwapChain4 *swap, UINT QueueCount, + void ReleaseSwapchainResources(IDXGISwapper *swapper, UINT QueueCount, IUnknown *const *ppPresentQueue, IUnknown **unwrappedQueues); ResourceId GetBackbufferResourceID() { return m_BBID; } diff --git a/renderdoc/driver/d3d12/d3d12_command_queue.h b/renderdoc/driver/d3d12/d3d12_command_queue.h index 7ea868c22..a67359ffc 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue.h +++ b/renderdoc/driver/d3d12/d3d12_command_queue.h @@ -68,18 +68,43 @@ struct WrappedID3D12DebugCommandQueue : public ID3D12DebugCommandQueue } }; +struct WrappedDownlevelQueue : public ID3D12CommandQueueDownlevel +{ + WrappedID3D12CommandQueue &m_pQueue; + + WrappedDownlevelQueue(WrappedID3D12CommandQueue &q) : m_pQueue(q) {} + ////////////////////////////// + // implement IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + ////////////////////////////// + // implement ID3D12CommandQueueDownlevel + virtual HRESULT STDMETHODCALLTYPE Present(ID3D12GraphicsCommandList *pOpenCommandList, + ID3D12Resource *pSourceTex2D, HWND hWindow, + D3D12_DOWNLEVEL_PRESENT_FLAGS Flags); +}; + class WrappedID3D12GraphicsCommandList; class WrappedID3D12CommandQueue : public ID3D12CommandQueue, public RefCounter12, - public ID3DDevice + public ID3DDevice, + public IDXGISwapper { friend class WrappedID3D12GraphicsCommandList; + ID3D12CommandQueueDownlevel *m_pDownlevel; + + WrappedDownlevelQueue m_WrappedDownlevel; + WrappedID3D12Device *m_pDevice; WrappedID3D12GraphicsCommandList *m_ReplayList; + ID3D12Resource *m_pPresentSource = NULL; + HWND m_pPresentHWND = NULL; + ResourceId m_ResourceID; D3D12ResourceRecord *m_QueueRecord; @@ -155,27 +180,48 @@ public: return NULL; } // the rest forward to the device - virtual void FirstFrame(WrappedIDXGISwapChain4 *swapChain) { m_pDevice->FirstFrame(swapChain); } + virtual void FirstFrame(IDXGISwapper *swapper) { m_pDevice->FirstFrame(swapper); } virtual void NewSwapchainBuffer(IUnknown *backbuffer) { m_pDevice->NewSwapchainBuffer(backbuffer); } - virtual void ReleaseSwapchainResources(WrappedIDXGISwapChain4 *swapChain, UINT QueueCount, + virtual void ReleaseSwapchainResources(IDXGISwapper *swapper, UINT QueueCount, IUnknown *const *ppPresentQueue, IUnknown **unwrappedQueues) { - m_pDevice->ReleaseSwapchainResources(swapChain, QueueCount, ppPresentQueue, unwrappedQueues); + m_pDevice->ReleaseSwapchainResources(swapper, QueueCount, ppPresentQueue, unwrappedQueues); } - virtual IUnknown *WrapSwapchainBuffer(WrappedIDXGISwapChain4 *swap, DXGI_SWAP_CHAIN_DESC *swapDesc, + virtual IUnknown *WrapSwapchainBuffer(IDXGISwapper *swapper, DXGI_FORMAT bufferFormat, UINT buffer, IUnknown *realSurface) { - return m_pDevice->WrapSwapchainBuffer(swap, swapDesc, buffer, realSurface); + return m_pDevice->WrapSwapchainBuffer(swapper, bufferFormat, buffer, realSurface); } - virtual HRESULT Present(WrappedIDXGISwapChain4 *swapChain, UINT SyncInterval, UINT Flags) + virtual HRESULT Present(IDXGISwapper *swapper, UINT SyncInterval, UINT Flags) { - return m_pDevice->Present(swapChain, SyncInterval, Flags); + return m_pDevice->Present(swapper, SyncInterval, Flags); } + // fake pretending to be a swapchain for when we're doing downlevel mega-hacky presents + virtual ID3DDevice *GetD3DDevice() { return this; } + virtual int GetNumBackbuffers() { return 1; } + virtual IUnknown **GetBackbuffers() { return (IUnknown **)&m_pPresentSource; } + virtual int GetLastPresentedBuffer() { return 0; } + virtual UINT GetWidth() + { + D3D12_RESOURCE_DESC desc = m_pPresentSource->GetDesc(); + return (UINT)desc.Width; + } + virtual UINT GetHeight() + { + D3D12_RESOURCE_DESC desc = m_pPresentSource->GetDesc(); + return desc.Height; + } + virtual DXGI_FORMAT GetFormat() + { + D3D12_RESOURCE_DESC desc = m_pPresentSource->GetDesc(); + return desc.Format; + } + virtual HWND GetHWND() { return m_pPresentHWND; } ////////////////////////////// // implement IUnknown @@ -252,7 +298,7 @@ public: virtual void ExecuteCommandListsInternal(UINT NumCommandLists, ID3D12CommandList *const *ppCommandLists, - bool InFrameCaptureBoundary); + bool InFrameCaptureBoundary, bool SkipRealExecute); IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, SetMarker, UINT Metadata, const void *pData, UINT Size); @@ -275,6 +321,11 @@ public: UINT64 *pGpuTimestamp, UINT64 *pCpuTimestamp); virtual D3D12_COMMAND_QUEUE_DESC STDMETHODCALLTYPE GetDesc() { return m_pReal->GetDesc(); } + ////////////////////////////// + // implement ID3D12CommandQueueDownlevel + virtual HRESULT STDMETHODCALLTYPE Present(ID3D12GraphicsCommandList *pOpenCommandList, + ID3D12Resource *pSourceTex2D, HWND hWindow, + D3D12_DOWNLEVEL_PRESENT_FLAGS Flags); }; template <> diff --git a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp index b5419470d..d33c09b91 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp @@ -324,12 +324,13 @@ bool WrappedID3D12CommandQueue::Serialise_ExecuteCommandLists(SerialiserType &se void WrappedID3D12CommandQueue::ExecuteCommandLists(UINT NumCommandLists, ID3D12CommandList *const *ppCommandLists) { - ExecuteCommandListsInternal(NumCommandLists, ppCommandLists, false); + ExecuteCommandListsInternal(NumCommandLists, ppCommandLists, false, false); } void WrappedID3D12CommandQueue::ExecuteCommandListsInternal(UINT NumCommandLists, ID3D12CommandList *const *ppCommandLists, - bool InFrameCaptureBoundary) + bool InFrameCaptureBoundary, + bool SkipRealExecute) { ID3D12CommandList **unwrapped = m_pDevice->GetTempArray(NumCommandLists); for(UINT i = 0; i < NumCommandLists; i++) @@ -344,7 +345,10 @@ void WrappedID3D12CommandQueue::ExecuteCommandListsInternal(UINT NumCommandLists if(IsActiveCapturing(m_State)) m_pDevice->AddCaptureSubmission(); - SERIALISE_TIME_CALL(m_pReal->ExecuteCommandLists(NumCommandLists, unwrapped)); + if(!SkipRealExecute) + { + SERIALISE_TIME_CALL(m_pReal->ExecuteCommandLists(NumCommandLists, unwrapped)); + } if(IsCaptureMode(m_State)) { @@ -766,6 +770,65 @@ HRESULT STDMETHODCALLTYPE WrappedID3D12CommandQueue::GetClockCalibration(UINT64 return m_pReal->GetClockCalibration(pGpuTimestamp, pCpuTimestamp); } +HRESULT STDMETHODCALLTYPE WrappedID3D12CommandQueue::Present( + _In_ ID3D12GraphicsCommandList *pOpenCommandList, _In_ ID3D12Resource *pSourceTex2D, + _In_ HWND hWindow, D3D12_DOWNLEVEL_PRESENT_FLAGS Flags) +{ + // D3D12 on windows 7 + if(!RenderDoc::Inst().GetCaptureOptions().allowVSync) + { + Flags = D3D12_DOWNLEVEL_PRESENT_FLAG_NONE; + } + + // store the timestamp, thread ID etc. Don't store the duration + SERIALISE_TIME_CALL(); + + if(IsCaptureMode(m_State)) + { + WrappedID3D12GraphicsCommandList *list = (WrappedID3D12GraphicsCommandList *)pOpenCommandList; + + // add a marker + const char str[] = "ID3D12CommandQueueDownlevel::Present()"; + list->SetMarker(PIX_EVENT_ANSI_VERSION, str, sizeof(str)); + + // the list is implicitly closed, serialise that + D3D12ResourceRecord *listRecord = GetRecord(list); + + { + CACHE_THREAD_SERIALISER(); + ser.SetDrawChunk(); + SCOPED_SERIALISE_CHUNK(D3D12Chunk::List_Close); + list->Serialise_Close(ser); + + listRecord->AddChunk(scope.Get()); + } + + listRecord->Bake(); + + // this queue implicitly submits the list, serialise that + ID3D12CommandList *submitlist = list; + ExecuteCommandListsInternal(1, &submitlist, false, true); + } + + if(m_pPresentHWND != NULL) + { + // don't let the device actually release any refs on the resource, just make it release internal + // resources + m_pPresentSource->AddRef(); + m_pDevice->ReleaseSwapchainResources(this, 0, NULL, NULL); + } + + m_pPresentSource = pSourceTex2D; + m_pPresentHWND = hWindow; + + m_pDevice->WrapSwapchainBuffer(this, GetFormat(), 0, m_pPresentSource); + + m_pDevice->Present(pOpenCommandList, this, + Flags == D3D12_DOWNLEVEL_PRESENT_FLAG_WAIT_FOR_VBLANK ? 1 : 0, 0); + + return m_pDownlevel->Present(Unwrap(pOpenCommandList), Unwrap(pSourceTex2D), hWindow, Flags); +} + INSTANTIATE_FUNCTION_SERIALISED( void, WrappedID3D12CommandQueue, UpdateTileMappings, ID3D12Resource *pResource, UINT NumResourceRegions, const D3D12_TILED_RESOURCE_COORDINATE *pResourceRegionStartCoordinates, diff --git a/renderdoc/driver/d3d12/d3d12_commands.cpp b/renderdoc/driver/d3d12/d3d12_commands.cpp index 6d44d4b35..d4d7fa473 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.cpp +++ b/renderdoc/driver/d3d12/d3d12_commands.cpp @@ -256,17 +256,43 @@ ULONG STDMETHODCALLTYPE WrappedID3D12DebugCommandList::Release() return 1; } +HRESULT STDMETHODCALLTYPE WrappedDownlevelQueue::QueryInterface(REFIID riid, void **ppvObject) +{ + return m_pQueue.QueryInterface(riid, ppvObject); +} + +ULONG STDMETHODCALLTYPE WrappedDownlevelQueue::AddRef() +{ + return m_pQueue.AddRef(); +} + +ULONG STDMETHODCALLTYPE WrappedDownlevelQueue::Release() +{ + return m_pQueue.Release(); +} + +HRESULT STDMETHODCALLTYPE WrappedDownlevelQueue::Present(ID3D12GraphicsCommandList *pOpenCommandList, + ID3D12Resource *pSourceTex2D, HWND hWindow, + D3D12_DOWNLEVEL_PRESENT_FLAGS Flags) +{ + return m_pQueue.Present(pOpenCommandList, pSourceTex2D, hWindow, Flags); +} + WrappedID3D12CommandQueue::WrappedID3D12CommandQueue(ID3D12CommandQueue *real, WrappedID3D12Device *device, CaptureState &state) - : RefCounter12(real), m_pDevice(device), m_State(state) + : RefCounter12(real), m_pDevice(device), m_State(state), m_WrappedDownlevel(*this) { if(RenderDoc::Inst().GetCrashHandler()) RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(WrappedID3D12CommandQueue)); m_WrappedDebug.m_pReal = NULL; + m_pDownlevel = NULL; if(m_pReal) + { m_pReal->QueryInterface(__uuidof(ID3D12DebugCommandQueue), (void **)&m_WrappedDebug.m_pReal); + m_pReal->QueryInterface(__uuidof(ID3D12CommandQueueDownlevel), (void **)&m_pDownlevel); + } if(RenderDoc::Inst().IsReplayApp()) { @@ -305,6 +331,8 @@ WrappedID3D12CommandQueue::~WrappedID3D12CommandQueue() m_pDevice->GetResourceManager()->ReleaseCurrentResource(GetResourceID()); m_pDevice->RemoveQueue(this); + SAFE_RELEASE(m_pDownlevel); + for(size_t i = 0; i < m_Cmd.m_IndirectBuffers.size(); i++) SAFE_RELEASE(m_Cmd.m_IndirectBuffers[i]); @@ -357,6 +385,19 @@ HRESULT STDMETHODCALLTYPE WrappedID3D12CommandQueue::QueryInterface(REFIID riid, AddRef(); return S_OK; } + else if(riid == __uuidof(ID3D12CommandQueueDownlevel)) + { + if(m_pDownlevel) + { + *ppvObject = &m_WrappedDownlevel; + AddRef(); + return S_OK; + } + else + { + return E_NOINTERFACE; + } + } else { WarnUnknownGUID("ID3D12CommandQueue", riid); diff --git a/renderdoc/driver/d3d12/d3d12_common.cpp b/renderdoc/driver/d3d12/d3d12_common.cpp index f04a0299b..73349f4a2 100644 --- a/renderdoc/driver/d3d12/d3d12_common.cpp +++ b/renderdoc/driver/d3d12/d3d12_common.cpp @@ -140,6 +140,10 @@ bool EnableD3D12DebugLayer(PFN_D3D12_GET_DEBUG_INTERFACE getDebugInterface) return true; } + else if(hr == DXGI_ERROR_SDK_COMPONENT_MISSING) + { + RDCWARN("Debug layer not available: DXGI_ERROR_SDK_COMPONENT_MISSING"); + } else { RDCERR("Couldn't enable debug layer: %x", hr); @@ -148,6 +152,38 @@ bool EnableD3D12DebugLayer(PFN_D3D12_GET_DEBUG_INTERFACE getDebugInterface) return false; } +HRESULT EnumAdapterByLuid(IDXGIFactory1 *factory, LUID luid, IDXGIAdapter **pAdapter) +{ + HRESULT hr = S_OK; + + *pAdapter = NULL; + + for(UINT i = 0; i < 10; i++) + { + IDXGIAdapter *adapter = NULL; + hr = factory->EnumAdapters(i, &adapter); + if(hr == S_OK && adapter) + { + DXGI_ADAPTER_DESC desc; + adapter->GetDesc(&desc); + + if(desc.AdapterLuid.LowPart == luid.LowPart && desc.AdapterLuid.HighPart == luid.HighPart) + { + *pAdapter = adapter; + return S_OK; + } + + adapter->Release(); + } + else + { + break; + } + } + + return E_FAIL; +} + D3D12InitParams::D3D12InitParams() { MinimumFeatureLevel = D3D_FEATURE_LEVEL_11_0; diff --git a/renderdoc/driver/d3d12/d3d12_common.h b/renderdoc/driver/d3d12/d3d12_common.h index a4c57c7e7..f1407c60a 100644 --- a/renderdoc/driver/d3d12/d3d12_common.h +++ b/renderdoc/driver/d3d12/d3d12_common.h @@ -28,6 +28,7 @@ #include "api/replay/renderdoc_replay.h" #include "core/core.h" +#include "driver/dx/official/D3D12Downlevel.h" #include "driver/dx/official/d3d12.h" #include "driver/dx/official/dxgi1_4.h" #include "driver/shaders/dxbc/dxbc_compile.h" @@ -53,6 +54,7 @@ struct D3D12MarkerRegion }; bool EnableD3D12DebugLayer(PFN_D3D12_GET_DEBUG_INTERFACE getDebugInterface = NULL); +HRESULT EnumAdapterByLuid(IDXGIFactory1 *factory, LUID luid, IDXGIAdapter **pAdapter); inline void SetObjName(ID3D12Object *obj, const std::string &utf8name) { diff --git a/renderdoc/driver/d3d12/d3d12_device.cpp b/renderdoc/driver/d3d12/d3d12_device.cpp index df8d02db3..8d803a42c 100644 --- a/renderdoc/driver/d3d12/d3d12_device.cpp +++ b/renderdoc/driver/d3d12/d3d12_device.cpp @@ -134,12 +134,35 @@ HRESULT STDMETHODCALLTYPE WrappedID3D12DebugDevice::QueryInterface(REFIID riid, return m_pDebug->QueryInterface(riid, ppvObject); } +HRESULT STDMETHODCALLTYPE WrappedDownlevelDevice::QueryInterface(REFIID riid, void **ppvObject) +{ + return m_pDevice.QueryInterface(riid, ppvObject); +} + +ULONG STDMETHODCALLTYPE WrappedDownlevelDevice::AddRef() +{ + return m_pDevice.AddRef(); +} + +ULONG STDMETHODCALLTYPE WrappedDownlevelDevice::Release() +{ + return m_pDevice.Release(); +} + +HRESULT STDMETHODCALLTYPE WrappedDownlevelDevice::QueryVideoMemoryInfo( + UINT NodeIndex, DXGI_MEMORY_SEGMENT_GROUP MemorySegmentGroup, + _Out_ DXGI_QUERY_VIDEO_MEMORY_INFO *pVideoMemoryInfo) +{ + return m_pDevice.QueryVideoMemoryInfo(NodeIndex, MemorySegmentGroup, pVideoMemoryInfo); +} + WrappedID3D12Device::WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitParams params, bool enabledDebugLayer) : m_RefCounter(realDevice, false), m_SoftRefCounter(NULL, false), m_pDevice(realDevice), - m_debugLayerEnabled(enabledDebugLayer) + m_debugLayerEnabled(enabledDebugLayer), + m_WrappedDownlevel(*this) { if(RenderDoc::Inst().GetCrashHandler()) RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(WrappedID3D12Device)); @@ -158,6 +181,7 @@ WrappedID3D12Device::WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitPara m_pDevice3 = NULL; m_pDevice4 = NULL; m_pDevice5 = NULL; + m_pDownlevel = NULL; if(m_pDevice) { m_pDevice->QueryInterface(__uuidof(ID3D12Device1), (void **)&m_pDevice1); @@ -165,6 +189,7 @@ WrappedID3D12Device::WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitPara m_pDevice->QueryInterface(__uuidof(ID3D12Device3), (void **)&m_pDevice3); m_pDevice->QueryInterface(__uuidof(ID3D12Device4), (void **)&m_pDevice4); m_pDevice->QueryInterface(__uuidof(ID3D12Device5), (void **)&m_pDevice5); + m_pDevice->QueryInterface(__uuidof(ID3D12DeviceDownlevel), (void **)&m_pDownlevel); for(size_t i = 0; i < ARRAY_COUNT(m_DescriptorIncrements); i++) m_DescriptorIncrements[i] = @@ -235,8 +260,8 @@ WrappedID3D12Device::WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitPara PFN_CREATE_DXGI_FACTORY createFunc = (PFN_CREATE_DXGI_FACTORY)GetProcAddress( GetModuleHandleA("dxgi.dll"), "CreateDXGIFactory1"); - IDXGIFactory4 *tmpFactory = NULL; - HRESULT hr = createFunc(__uuidof(IDXGIFactory4), (void **)&tmpFactory); + IDXGIFactory1 *tmpFactory = NULL; + HRESULT hr = createFunc(__uuidof(IDXGIFactory1), (void **)&tmpFactory); if(FAILED(hr)) { @@ -246,8 +271,7 @@ WrappedID3D12Device::WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitPara if(tmpFactory) { IDXGIAdapter *pDXGIAdapter = NULL; - hr = tmpFactory->EnumAdapterByLuid(m_pDevice->GetAdapterLuid(), __uuidof(IDXGIAdapter), - (void **)&pDXGIAdapter); + hr = EnumAdapterByLuid(tmpFactory, m_pDevice->GetAdapterLuid(), &pDXGIAdapter); if(FAILED(hr)) { @@ -432,6 +456,7 @@ WrappedID3D12Device::~WrappedID3D12Device() SAFE_DELETE(m_ResourceManager); + SAFE_RELEASE(m_pDownlevel); SAFE_RELEASE(m_pDevice5); SAFE_RELEASE(m_pDevice4); SAFE_RELEASE(m_pDevice3); @@ -614,6 +639,19 @@ HRESULT WrappedID3D12Device::QueryInterface(REFIID riid, void **ppvObject) return E_NOINTERFACE; } } + else if(riid == __uuidof(ID3D12DeviceDownlevel)) + { + if(m_pDownlevel) + { + *ppvObject = &m_WrappedDownlevel; + AddRef(); + return S_OK; + } + else + { + return E_NOINTERFACE; + } + } else if(riid == __uuidof(ID3D12InfoQueue)) { RDCWARN( @@ -783,17 +821,12 @@ void WrappedID3D12Device::CheckForDeath() } } -void WrappedID3D12Device::FirstFrame(WrappedIDXGISwapChain4 *swap) +void WrappedID3D12Device::FirstFrame(IDXGISwapper *swapper) { - DXGI_SWAP_CHAIN_DESC swapdesc = {}; - - if(swap) - swapdesc = swap->GetDescWithHWND(); - // if we have to capture the first frame, begin capturing immediately if(IsBackgroundCapturing(m_State) && RenderDoc::Inst().ShouldTriggerCapture(0)) { - RenderDoc::Inst().StartFrameCapture((ID3D12Device *)this, swapdesc.OutputWindow); + RenderDoc::Inst().StartFrameCapture((ID3D12Device *)this, swapper->GetHWND()); m_AppControlledCapture = false; } @@ -805,7 +838,7 @@ void WrappedID3D12Device::ApplyBarriers(std::vector &bar GetResourceManager()->ApplyBarriers(barriers, m_ResourceStates); } -void WrappedID3D12Device::ReleaseSwapchainResources(WrappedIDXGISwapChain4 *swap, UINT QueueCount, +void WrappedID3D12Device::ReleaseSwapchainResources(IDXGISwapper *swapper, UINT QueueCount, IUnknown *const *ppPresentQueue, IUnknown **unwrappedQueues) { @@ -820,9 +853,9 @@ void WrappedID3D12Device::ReleaseSwapchainResources(WrappedIDXGISwapChain4 *swap } } - for(int i = 0; i < swap->GetNumBackbuffers(); i++) + for(int i = 0; i < swapper->GetNumBackbuffers(); i++) { - ID3D12Resource *res = (ID3D12Resource *)swap->GetBackbuffers()[i]; + ID3D12Resource *res = (ID3D12Resource *)swapper->GetBackbuffers()[i]; if(!res) continue; @@ -832,19 +865,19 @@ void WrappedID3D12Device::ReleaseSwapchainResources(WrappedIDXGISwapChain4 *swap SAFE_RELEASE(wrapped); } - if(swap) + HWND wnd = swapper->GetHWND(); + + if(wnd) { - DXGI_SWAP_CHAIN_DESC desc = swap->GetDescWithHWND(); + Keyboard::RemoveInputWindow(wnd); - Keyboard::RemoveInputWindow(desc.OutputWindow); - - RenderDoc::Inst().RemoveFrameCapturer((ID3D12Device *)this, desc.OutputWindow); + RenderDoc::Inst().RemoveFrameCapturer((ID3D12Device *)this, wnd); } - auto it = m_SwapChains.find(swap); + auto it = m_SwapChains.find(swapper); if(it != m_SwapChains.end()) { - for(int i = 0; i < swap->GetNumBackbuffers(); i++) + for(int i = 0; i < swapper->GetNumBackbuffers(); i++) FreeRTV(it->second.rtvs[i]); m_SwapChains.erase(it); @@ -863,9 +896,8 @@ void WrappedID3D12Device::NewSwapchainBuffer(IUnknown *backbuffer) } template -bool WrappedID3D12Device::Serialise_WrapSwapchainBuffer(SerialiserType &ser, - WrappedIDXGISwapChain4 *swap, - DXGI_SWAP_CHAIN_DESC *swapDesc, UINT Buffer, +bool WrappedID3D12Device::Serialise_WrapSwapchainBuffer(SerialiserType &ser, IDXGISwapper *swapper, + DXGI_FORMAT bufferFormat, UINT Buffer, IUnknown *realSurface) { WrappedID3D12Resource1 *pRes = (WrappedID3D12Resource1 *)realSurface; @@ -928,60 +960,70 @@ bool WrappedID3D12Device::Serialise_WrapSwapchainBuffer(SerialiserType &ser, return true; } -IUnknown *WrappedID3D12Device::WrapSwapchainBuffer(WrappedIDXGISwapChain4 *swap, - DXGI_SWAP_CHAIN_DESC *swapDesc, UINT buffer, - IUnknown *realSurface) +IUnknown *WrappedID3D12Device::WrapSwapchainBuffer(IDXGISwapper *swapper, DXGI_FORMAT bufferFormat, + UINT buffer, IUnknown *realSurface) { - if(GetResourceManager()->HasWrapper((ID3D12DeviceChild *)realSurface)) + ID3D12Resource *pRes = NULL; + + ID3D12Resource *query = NULL; + realSurface->QueryInterface(__uuidof(ID3D12Resource), (void **)&query); + if(query) + query->Release(); + + if(GetResourceManager()->HasWrapper(query)) { - ID3D12Resource *tex = - (ID3D12Resource *)GetResourceManager()->GetWrapper((ID3D12DeviceChild *)realSurface); - tex->AddRef(); + pRes = (ID3D12Resource *)GetResourceManager()->GetWrapper(query); + pRes->AddRef(); realSurface->Release(); - - return tex; } - - ID3D12Resource *pRes = new WrappedID3D12Resource1((ID3D12Resource *)realSurface, this); - - ResourceId id = GetResID(pRes); - - // there shouldn't be a resource record for this texture as it wasn't created via - // Create*Resource - RDCASSERT(id != ResourceId() && !GetResourceManager()->HasResourceRecord(id)); - - if(IsCaptureMode(m_State)) + else if(WrappedID3D12Resource1::IsAlloc(query)) { - D3D12ResourceRecord *record = GetResourceManager()->AddResourceRecord(id); - record->type = Resource_Resource; - record->DataInSerialiser = false; - record->Length = 0; + // this could be possible if we're doing downlevel presenting + pRes = query; + } + else + { + pRes = new WrappedID3D12Resource1((ID3D12Resource *)realSurface, this); - WrappedID3D12Resource1 *wrapped = (WrappedID3D12Resource1 *)pRes; + ResourceId id = GetResID(pRes); - wrapped->SetResourceRecord(record); - - WriteSerialiser &ser = GetThreadSerialiser(); - - SCOPED_SERIALISE_CHUNK(D3D12Chunk::CreateSwapBuffer); - - Serialise_WrapSwapchainBuffer(ser, swap, swapDesc, buffer, pRes); - - record->AddChunk(scope.Get()); + // there shouldn't be a resource record for this texture as it wasn't created via + // Create*Resource + RDCASSERT(id != ResourceId() && !GetResourceManager()->HasResourceRecord(id)); + if(IsCaptureMode(m_State)) { - SCOPED_LOCK(m_ResourceStatesLock); - SubresourceStateVector &states = m_ResourceStates[id]; + D3D12ResourceRecord *record = GetResourceManager()->AddResourceRecord(id); + record->type = Resource_Resource; + record->DataInSerialiser = false; + record->Length = 0; - states.resize(1, D3D12_RESOURCE_STATE_PRESENT); + WrappedID3D12Resource1 *wrapped = (WrappedID3D12Resource1 *)pRes; + + wrapped->SetResourceRecord(record); + + WriteSerialiser &ser = GetThreadSerialiser(); + + SCOPED_SERIALISE_CHUNK(D3D12Chunk::CreateSwapBuffer); + + Serialise_WrapSwapchainBuffer(ser, swapper, bufferFormat, buffer, pRes); + + record->AddChunk(scope.Get()); + + { + SCOPED_LOCK(m_ResourceStatesLock); + SubresourceStateVector &states = m_ResourceStates[id]; + + states.resize(1, D3D12_RESOURCE_STATE_PRESENT); + } } } if(IsCaptureMode(m_State)) { D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = GetSRGBFormat(swapDesc->BufferDesc.Format); + rtvDesc.Format = GetSRGBFormat(bufferFormat); rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; rtvDesc.Texture2D.MipSlice = 0; rtvDesc.Texture2D.PlaneSlice = 0; @@ -991,23 +1033,20 @@ IUnknown *WrappedID3D12Device::WrapSwapchainBuffer(WrappedIDXGISwapChain4 *swap, if(rtv.ptr != 0) CreateRenderTargetView(pRes, NULL, rtv); - m_SwapChains[swap].rtvs[buffer] = rtv; + m_SwapChains[swapper].rtvs[buffer] = rtv; - ID3DDevice *swapQ = swap->GetD3DDevice(); + ID3DDevice *swapQ = swapper->GetD3DDevice(); RDCASSERT(WrappedID3D12CommandQueue::IsAlloc(swapQ)); - m_SwapChains[swap].queue = (WrappedID3D12CommandQueue *)swapQ; - - // start at -1 so that we know we've never presented before - m_SwapChains[swap].lastPresentedBuffer = -1; + m_SwapChains[swapper].queue = (WrappedID3D12CommandQueue *)swapQ; } - if(swap) + HWND wnd = swapper->GetHWND(); + + if(wnd) { - DXGI_SWAP_CHAIN_DESC sdesc = swap->GetDescWithHWND(); + Keyboard::AddInputWindow(wnd); - Keyboard::AddInputWindow(sdesc.OutputWindow); - - RenderDoc::Inst().AddFrameCapturer((ID3D12Device *)this, sdesc.OutputWindow, this); + RenderDoc::Inst().AddFrameCapturer((ID3D12Device *)this, wnd, this); } return pRes; @@ -1330,7 +1369,8 @@ void WrappedID3D12Device::WriteToSubresource(ID3D12Resource *Resource, UINT Subr } } -HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain4 *swap, UINT SyncInterval, UINT Flags) +HRESULT WrappedID3D12Device::Present(ID3D12GraphicsCommandList *pOverlayCommandList, + IDXGISwapper *swapper, UINT SyncInterval, UINT Flags) { if((Flags & DXGI_PRESENT_TEST) != 0) return S_OK; @@ -1340,22 +1380,9 @@ HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain4 *swap, UINT SyncInte m_FrameCounter++; // first present becomes frame #1, this function is at the end of the frame - DXGI_SWAP_CHAIN_DESC swapdesc = swap->GetDescWithHWND(); - bool activeWindow = RenderDoc::Inst().IsActiveWindow((ID3D12Device *)this, swapdesc.OutputWindow); + bool activeWindow = RenderDoc::Inst().IsActiveWindow((ID3D12Device *)this, swapper->GetHWND()); - m_LastSwap = swap; - - if(swapdesc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD) - { - // discard always presents from 0 - m_SwapChains[swap].lastPresentedBuffer = 0; - } - else - { - // other modes use each buffer in turn - m_SwapChains[swap].lastPresentedBuffer++; - m_SwapChains[swap].lastPresentedBuffer %= swapdesc.BufferCount; - } + m_LastSwap = swapper; if(IsBackgroundCapturing(m_State)) { @@ -1363,20 +1390,27 @@ HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain4 *swap, UINT SyncInte if(overlay & eRENDERDOC_Overlay_Enabled) { - SwapPresentInfo &swapInfo = m_SwapChains[swap]; - D3D12_CPU_DESCRIPTOR_HANDLE rtv = swapInfo.rtvs[swapInfo.lastPresentedBuffer]; + SwapPresentInfo &swapInfo = m_SwapChains[swapper]; + D3D12_CPU_DESCRIPTOR_HANDLE rtv = swapInfo.rtvs[swapper->GetLastPresentedBuffer()]; if(rtv.ptr) { - m_TextRenderer->SetOutputDimensions(swapdesc.BufferDesc.Width, swapdesc.BufferDesc.Height, - swapdesc.BufferDesc.Format); + m_TextRenderer->SetOutputDimensions(swapper->GetWidth(), swapper->GetHeight(), + swapper->GetFormat()); - ID3D12GraphicsCommandList *list = GetNewList(); + ID3D12GraphicsCommandList *list = pOverlayCommandList; + bool submitlist = false; + + if(!list) + { + list = GetNewList(); + submitlist = true; + } // buffer will be in common for presentation, transition to render target D3D12_RESOURCE_BARRIER barrier = {}; barrier.Transition.pResource = - (ID3D12Resource *)swap->GetBackbuffers()[swapInfo.lastPresentedBuffer]; + (ID3D12Resource *)swapper->GetBackbuffers()[swapper->GetLastPresentedBuffer()]; barrier.Transition.Subresource = 0; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; @@ -1399,10 +1433,13 @@ HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain4 *swap, UINT SyncInte std::swap(barrier.Transition.StateBefore, barrier.Transition.StateAfter); list->ResourceBarrier(1, &barrier); - list->Close(); + if(submitlist) + { + list->Close(); - ExecuteLists(swapInfo.queue); - FlushLists(false, swapInfo.queue); + ExecuteLists(swapInfo.queue); + FlushLists(false, swapInfo.queue); + } } } } @@ -1418,11 +1455,11 @@ HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain4 *swap, UINT SyncInte // kill any current capture that isn't application defined if(IsActiveCapturing(m_State) && !m_AppControlledCapture) - RenderDoc::Inst().EndFrameCapture((ID3D12Device *)this, swapdesc.OutputWindow); + RenderDoc::Inst().EndFrameCapture((ID3D12Device *)this, swapper->GetHWND()); if(IsBackgroundCapturing(m_State) && RenderDoc::Inst().ShouldTriggerCapture(m_FrameCounter)) { - RenderDoc::Inst().StartFrameCapture((ID3D12Device *)this, swapdesc.OutputWindow); + RenderDoc::Inst().StartFrameCapture((ID3D12Device *)this, swapper->GetHWND()); m_AppControlledCapture = false; } @@ -1565,24 +1602,22 @@ bool WrappedID3D12Device::EndFrameCapture(void *dev, void *wnd) if(!IsActiveCapturing(m_State)) return true; - WrappedIDXGISwapChain4 *swap = NULL; + IDXGISwapper *swapper = NULL; SwapPresentInfo swapInfo = {}; if(wnd) { for(auto it = m_SwapChains.begin(); it != m_SwapChains.end(); ++it) { - DXGI_SWAP_CHAIN_DESC swapDesc = it->first->GetDescWithHWND(); - - if(swapDesc.OutputWindow == wnd) + if(it->first->GetHWND() == wnd) { - swap = it->first; + swapper = it->first; swapInfo = it->second; break; } } - if(swap == NULL) + if(swapper == NULL) { RDCERR("Output window %p provided for frame capture corresponds with no known swap chain", wnd); return false; @@ -1593,14 +1628,14 @@ bool WrappedID3D12Device::EndFrameCapture(void *dev, void *wnd) ID3D12Resource *backbuffer = NULL; - if(swap == NULL) + if(swapper == NULL) { - swap = m_LastSwap; - swapInfo = m_SwapChains[swap]; + swapper = m_LastSwap; + swapInfo = m_SwapChains[swapper]; } - if(swap != NULL) - backbuffer = (ID3D12Resource *)swap->GetBackbuffers()[swapInfo.lastPresentedBuffer]; + if(swapper != NULL) + backbuffer = (ID3D12Resource *)swapper->GetBackbuffers()[swapper->GetLastPresentedBuffer()]; std::vector queues; RDCFile *rdc = NULL; @@ -2266,6 +2301,13 @@ void WrappedID3D12Device::SetName(ID3D12DeviceChild *pResource, const char *Name } } +HRESULT STDMETHODCALLTYPE WrappedID3D12Device::QueryVideoMemoryInfo( + UINT NodeIndex, DXGI_MEMORY_SEGMENT_GROUP MemorySegmentGroup, + _Out_ DXGI_QUERY_VIDEO_MEMORY_INFO *pVideoMemoryInfo) +{ + return m_pDownlevel->QueryVideoMemoryInfo(NodeIndex, MemorySegmentGroup, pVideoMemoryInfo); +} + byte *WrappedID3D12Device::GetTempMemory(size_t s) { TempMem *mem = (TempMem *)Threading::GetTLSValue(tempMemoryTLSSlot); @@ -2577,8 +2619,13 @@ void WrappedID3D12Device::ExecuteList(ID3D12GraphicsCommandList4 *list, queue = GetQueue(); ID3D12CommandList *l = list; - queue->ExecuteCommandListsInternal(1, &l, InFrameCaptureBoundary); + queue->ExecuteCommandListsInternal(1, &l, InFrameCaptureBoundary, false); + MarkListExecuted(list); +} + +void WrappedID3D12Device::MarkListExecuted(ID3D12GraphicsCommandList4 *list) +{ for(auto it = m_InternalCmds.pendingcmds.begin(); it != m_InternalCmds.pendingcmds.end(); ++it) { if(list == *it) @@ -2605,7 +2652,7 @@ void WrappedID3D12Device::ExecuteLists(WrappedID3D12CommandQueue *queue, bool In if(queue == NULL) queue = GetQueue(); - queue->ExecuteCommandListsInternal((UINT)cmds.size(), &cmds[0], InFrameCaptureBoundary); + queue->ExecuteCommandListsInternal((UINT)cmds.size(), &cmds[0], InFrameCaptureBoundary, false); m_InternalCmds.submittedcmds.insert(m_InternalCmds.submittedcmds.end(), m_InternalCmds.pendingcmds.begin(), @@ -2693,7 +2740,7 @@ bool WrappedID3D12Device::ProcessChunk(ReadSerialiser &ser, D3D12Chunk context) return Serialise_SetShaderDebugPath(ser, NULL, NULL); break; case D3D12Chunk::CreateSwapBuffer: - return Serialise_WrapSwapchainBuffer(ser, NULL, NULL, 0, NULL); + return Serialise_WrapSwapchainBuffer(ser, NULL, DXGI_FORMAT_UNKNOWN, 0, NULL); break; case D3D12Chunk::Device_CreatePipelineState: return Serialise_CreatePipelineState(ser, NULL, IID(), NULL); diff --git a/renderdoc/driver/d3d12/d3d12_device.h b/renderdoc/driver/d3d12/d3d12_device.h index f8fb07fdc..665635aa4 100644 --- a/renderdoc/driver/d3d12/d3d12_device.h +++ b/renderdoc/driver/d3d12/d3d12_device.h @@ -268,6 +268,23 @@ struct DummyID3D12DebugDevice : public ID3D12DebugDevice2, public ID3D12DebugDev } }; +struct WrappedDownlevelDevice : public ID3D12DeviceDownlevel +{ + WrappedID3D12Device &m_pDevice; + + WrappedDownlevelDevice(WrappedID3D12Device &dev) : m_pDevice(dev) {} + ////////////////////////////// + // implement IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + ////////////////////////////// + // implement ID3D12DeviceDownlevel + virtual HRESULT STDMETHODCALLTYPE + QueryVideoMemoryInfo(UINT NodeIndex, DXGI_MEMORY_SEGMENT_GROUP MemorySegmentGroup, + _Out_ DXGI_QUERY_VIDEO_MEMORY_INFO *pVideoMemoryInfo); +}; + class WrappedID3D12CommandQueue; #define IMPLEMENT_FUNCTION_THREAD_SERIALISED(ret, func, ...) \ @@ -284,6 +301,7 @@ private: ID3D12Device3 *m_pDevice3; ID3D12Device4 *m_pDevice4; ID3D12Device5 *m_pDevice5; + ID3D12DeviceDownlevel *m_pDownlevel; // list of all queues being captured std::vector m_Queues; @@ -299,6 +317,8 @@ private: HANDLE m_GPUSyncHandle; UINT64 m_GPUSyncCounter; + WrappedDownlevelDevice m_WrappedDownlevel; + std::vector m_CommandAllocators; D3D12_CPU_DESCRIPTOR_HANDLE AllocRTV(); @@ -405,14 +425,12 @@ private: D3D12_CPU_DESCRIPTOR_HANDLE rtvs[8]; WrappedID3D12CommandQueue *queue; - - int32_t lastPresentedBuffer; }; - std::map m_SwapChains; + std::map m_SwapChains; std::map m_BackbufferFormat; - WrappedIDXGISwapChain4 *m_LastSwap; + IDXGISwapper *m_LastSwap; D3D12_FEATURE_DATA_D3D12_OPTIONS m_D3D12Opts; D3D12_FEATURE_DATA_D3D12_OPTIONS1 m_D3D12Opts1; @@ -460,7 +478,7 @@ public: ResourceId GetResourceID() { return m_ResourceID; } Threading::RWLock &GetCapTransitionLock() { return m_CapTransitionLock; } void ReleaseSwapchainResources(IDXGISwapChain *swap, IUnknown **backbuffers, int numBackbuffers); - void FirstFrame(WrappedIDXGISwapChain4 *swap); + void FirstFrame(IDXGISwapper *swapper); FrameRecord &GetFrameRecord() { return m_FrameRecord; } const DrawcallDescription *GetDrawcall(uint32_t eventId); @@ -551,6 +569,7 @@ public: void ExecuteList(ID3D12GraphicsCommandList4 *list, WrappedID3D12CommandQueue *queue = NULL, bool InFrameCaptureBoundary = false); + void MarkListExecuted(ID3D12GraphicsCommandList4 *list); void ExecuteLists(WrappedID3D12CommandQueue *queue = NULL, bool InFrameCaptureBoundary = false); void FlushLists(bool forceSync = false, ID3D12CommandQueue *queue = NULL); @@ -611,13 +630,17 @@ public: return NULL; } // Swap Chain - IMPLEMENT_FUNCTION_THREAD_SERIALISED(IUnknown *, WrapSwapchainBuffer, - WrappedIDXGISwapChain4 *swap, DXGI_SWAP_CHAIN_DESC *desc, - UINT buffer, IUnknown *realSurface); - HRESULT Present(WrappedIDXGISwapChain4 *swap, UINT SyncInterval, UINT Flags); + IMPLEMENT_FUNCTION_THREAD_SERIALISED(IUnknown *, WrapSwapchainBuffer, IDXGISwapper *swapper, + DXGI_FORMAT bufferFormat, UINT buffer, IUnknown *realSurface); + HRESULT Present(ID3D12GraphicsCommandList *pOverlayCommandList, IDXGISwapper *swapper, + UINT SyncInterval, UINT Flags); + HRESULT Present(IDXGISwapper *swapper, UINT SyncInterval, UINT Flags) + { + return Present(NULL, swapper, SyncInterval, Flags); + } void NewSwapchainBuffer(IUnknown *backbuffer); - void ReleaseSwapchainResources(WrappedIDXGISwapChain4 *swap, UINT QueueCount, + void ReleaseSwapchainResources(IDXGISwapper *swapper, UINT QueueCount, IUnknown *const *ppPresentQueue, IUnknown **unwrappedQueues); void Map(ID3D12Resource *Resource, UINT Subresource); @@ -1015,4 +1038,10 @@ public: virtual D3D12_DRIVER_MATCHING_IDENTIFIER_STATUS STDMETHODCALLTYPE CheckDriverMatchingIdentifier( _In_ D3D12_SERIALIZED_DATA_TYPE SerializedDataType, _In_ const D3D12_SERIALIZED_DATA_DRIVER_MATCHING_IDENTIFIER *pIdentifierToCheck); + + ////////////////////////////// + // implement ID3D12DeviceDownlevel + virtual HRESULT STDMETHODCALLTYPE + QueryVideoMemoryInfo(UINT NodeIndex, DXGI_MEMORY_SEGMENT_GROUP MemorySegmentGroup, + _Out_ DXGI_QUERY_VIDEO_MEMORY_INFO *pVideoMemoryInfo); }; diff --git a/renderdoc/driver/d3d12/d3d12_hooks.cpp b/renderdoc/driver/d3d12/d3d12_hooks.cpp index 61d0e7c83..f33eab1fb 100644 --- a/renderdoc/driver/d3d12/d3d12_hooks.cpp +++ b/renderdoc/driver/d3d12/d3d12_hooks.cpp @@ -28,6 +28,8 @@ #include "d3d12_command_queue.h" #include "d3d12_device.h" +#include "driver/dx/official/D3D11On12On7.h" + #if ENABLED(RDOC_X64) #define BIT_SPECIFIC_DLL(dll32, dll64) dll64 @@ -52,6 +54,60 @@ ID3DDevice *GetD3D12DeviceIfAlloc(IUnknown *dev) return NULL; } +class WrappedD3D11On12On7 : public RefCounter12 +{ +public: + WrappedD3D11On12On7(ID3D11On12On7 *real) : RefCounter12(real) {} + virtual ~WrappedD3D11On12On7() {} + ////////////////////////////// + // Implement IUnknown + ULONG STDMETHODCALLTYPE AddRef() { return RefCounter12::AddRef(); } + ULONG STDMETHODCALLTYPE Release() { return RefCounter12::Release(); } + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(IUnknown)) + { + *ppvObject = (IUnknown *)this; + AddRef(); + return S_OK; + } + + return E_NOINTERFACE; + } + + ////////////////////////////// + // Implement ID3D11On12On7 + + // Enables usage similar to D3D11On12CreateDevice. + void STDMETHODCALLTYPE SetThreadDeviceCreationParams(ID3D12Device *pDevice, + ID3D12CommandQueue *pGraphicsQueue) + { + RDCASSERT(WrappedID3D12Device::IsAlloc(pDevice)); + m_pReal->SetThreadDeviceCreationParams(((WrappedID3D12Device *)pDevice)->GetReal(), + Unwrap(pGraphicsQueue)); + } + + // Enables usage similar to ID3D11On12Device::CreateWrappedResource. + // Note that the D3D11 resource creation parameters should be similar to the D3D12 resource, + // or else unexpected/undefined behavior may occur. + void STDMETHODCALLTYPE SetThreadResourceCreationParams(ID3D12Resource *pResource) + { + m_pReal->SetThreadResourceCreationParams(Unwrap(pResource)); + } + + ID3D11On12On7Device *STDMETHODCALLTYPE GetThreadLastCreatedDevice() + { + // don't need to wrap/unwrap, it only deals with ID3D11On12On7Resource + return m_pReal->GetThreadLastCreatedDevice(); + } + + ID3D11On12On7Resource *STDMETHODCALLTYPE GetThreadLastCreatedResource() + { + // don't need to wrap/unwrap + return m_pReal->GetThreadLastCreatedResource(); + } +}; + // dummy class to present to the user, while we maintain control // // The inheritance is awful for these. See WrappedID3D12DebugDevice for why there are multiple @@ -145,6 +201,8 @@ public: GetDebugInterface.Register("d3d12.dll", "D3D12GetDebugInterface", D3D12GetDebugInterface_hook); EnableExperimentalFeatures.Register("d3d12.dll", "D3D12EnableExperimentalFeatures", D3D12EnableExperimentalFeatures_hook); + GetD3D11On12On7.Register("d3d11on12.dll", "GetD3D11On12On7Interface", + GetD3D11On12On7Interface_hook); } private: @@ -165,6 +223,7 @@ private: HookedFunction GetDebugInterface; HookedFunction CreateDevice; HookedFunction EnableExperimentalFeatures; + HookedFunction GetD3D11On12On7; // re-entrancy detection (can happen in rare cases with e.g. fraps) bool m_InsideCreate = false; @@ -325,6 +384,14 @@ private: return E_NOINTERFACE; } + static HRESULT WINAPI GetD3D11On12On7Interface_hook(ID3D11On12On7 **ppIface) + { + ID3D11On12On7 *real = NULL; + d3d12hooks.GetD3D11On12On7()(&real); + *ppIface = (ID3D11On12On7 *)(new WrappedD3D11On12On7(real)); + return S_OK; + } + static HRESULT WINAPI D3D12GetDebugInterface_hook(REFIID riid, void **ppvDebug) { if(riid != __uuidof(ID3D12Debug)) diff --git a/renderdoc/driver/d3d12/d3d12_outputwindow.cpp b/renderdoc/driver/d3d12/d3d12_outputwindow.cpp index 3e927c0f9..609ef11e4 100644 --- a/renderdoc/driver/d3d12/d3d12_outputwindow.cpp +++ b/renderdoc/driver/d3d12/d3d12_outputwindow.cpp @@ -33,9 +33,9 @@ void D3D12Replay::OutputWindow::MakeRTV(bool msaa) D3D12_RESOURCE_DESC texDesc = {}; - if(bb[0]) + if(bbDesc.Width) { - texDesc = bb[0]->GetDesc(); + texDesc = bbDesc; texDesc.SampleDesc.Count = msaa ? D3D12_MSAA_SAMPLECOUNT : 1; @@ -46,16 +46,17 @@ void D3D12Replay::OutputWindow::MakeRTV(bool msaa) texDesc.DepthOrArraySize = 1; texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; texDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; - texDesc.Height = height; texDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; texDesc.MipLevels = 1; texDesc.SampleDesc.Count = 1; texDesc.SampleDesc.Quality = 0; - texDesc.Width = width; multisampled = false; } + texDesc.Height = height; + texDesc.Width = width; + texDesc.Alignment = 0; texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; texDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; @@ -191,7 +192,15 @@ uint64_t D3D12Replay::MakeOutputWindow(WindowingData window, bool depth) HRESULT hr = S_OK; - hr = m_pFactory->CreateSwapChain(m_pDevice->GetQueue(), &swapDesc, &outw.swap); + // on 12On7 just skip creating the swapchain + if(m_D3D12On7) + { + outw.swap = NULL; + } + else + { + hr = m_pFactory->CreateSwapChain(m_pDevice->GetQueue(), &swapDesc, &outw.swap); + } if(FAILED(hr)) { @@ -199,8 +208,27 @@ uint64_t D3D12Replay::MakeOutputWindow(WindowingData window, bool depth) return 0; } - outw.swap->GetBuffer(0, __uuidof(ID3D12Resource), (void **)&outw.bb[0]); - outw.swap->GetBuffer(1, __uuidof(ID3D12Resource), (void **)&outw.bb[1]); + if(outw.swap) + { + outw.swap->GetBuffer(0, __uuidof(ID3D12Resource), (void **)&outw.bb[0]); + outw.swap->GetBuffer(1, __uuidof(ID3D12Resource), (void **)&outw.bb[1]); + outw.bbDesc = outw.bb[0]->GetDesc(); + } + else + { + outw.bbDesc.DepthOrArraySize = 1; + outw.bbDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + outw.bbDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + outw.bbDesc.Height = outw.height; + outw.bbDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + outw.bbDesc.MipLevels = 1; + outw.bbDesc.SampleDesc.Count = 1; + outw.bbDesc.SampleDesc.Quality = 0; + outw.bbDesc.Width = outw.width; + outw.bbDesc.Alignment = 0; + outw.bbDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + outw.bbDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + } } else { @@ -262,7 +290,7 @@ bool D3D12Replay::CheckResizeOutputWindow(uint64_t id) OutputWindow &outw = m_OutputWindows[id]; - if(outw.wnd == NULL || outw.swap == NULL) + if(outw.wnd == NULL || (outw.swap == NULL && !m_D3D12On7)) return false; RECT rect; @@ -283,20 +311,23 @@ bool D3D12Replay::CheckResizeOutputWindow(uint64_t id) SAFE_RELEASE(outw.bb[0]); SAFE_RELEASE(outw.bb[1]); - DXGI_SWAP_CHAIN_DESC desc; - outw.swap->GetDesc(&desc); - - HRESULT hr = outw.swap->ResizeBuffers(desc.BufferCount, outw.width, outw.height, - desc.BufferDesc.Format, desc.Flags); - - if(FAILED(hr)) + if(outw.swap) { - RDCERR("Failed to resize swap chain, HRESULT: %s", ToStr(hr).c_str()); - return true; - } + DXGI_SWAP_CHAIN_DESC desc; + outw.swap->GetDesc(&desc); - outw.swap->GetBuffer(0, __uuidof(ID3D12Resource), (void **)&outw.bb[0]); - outw.swap->GetBuffer(1, __uuidof(ID3D12Resource), (void **)&outw.bb[1]); + HRESULT hr = outw.swap->ResizeBuffers(desc.BufferCount, outw.width, outw.height, + desc.BufferDesc.Format, desc.Flags); + + if(FAILED(hr)) + { + RDCERR("Failed to resize swap chain, HRESULT: %s", ToStr(hr).c_str()); + return true; + } + + outw.swap->GetBuffer(0, __uuidof(ID3D12Resource), (void **)&outw.bb[0]); + outw.swap->GetBuffer(1, __uuidof(ID3D12Resource), (void **)&outw.bb[1]); + } outw.bbIdx = 0; @@ -524,24 +555,26 @@ void D3D12Replay::FlipOutputWindow(uint64_t id) OutputWindow &outw = m_OutputWindows[id]; - if(m_OutputWindows[id].bb[0] == NULL || m_OutputWindows[id].swap == NULL) + if(!m_D3D12On7 && (m_OutputWindows[id].bb[0] == NULL || m_OutputWindows[id].swap == NULL)) return; - D3D12_RESOURCE_BARRIER barriers[3]; - RDCEraseEl(barriers); + if(m_OutputWindows[id].col == NULL) + return; - barriers[0].Transition.pResource = outw.col; - barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; - barriers[0].Transition.StateAfter = + D3D12_RESOURCE_BARRIER colbarrier = {}, bbbarrier = {}, resolvebarrier = {}; + + colbarrier.Transition.pResource = outw.col; + colbarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; + colbarrier.Transition.StateAfter = outw.multisampled ? D3D12_RESOURCE_STATE_RESOLVE_SOURCE : D3D12_RESOURCE_STATE_COPY_SOURCE; - barriers[1].Transition.pResource = outw.bb[outw.bbIdx]; - barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; - barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST; + bbbarrier.Transition.pResource = outw.bb[outw.bbIdx]; + bbbarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; + bbbarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST; - barriers[2].Transition.pResource = outw.colResolve; - barriers[2].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE; - barriers[2].Transition.StateAfter = D3D12_RESOURCE_STATE_RESOLVE_DEST; + resolvebarrier.Transition.pResource = outw.colResolve; + resolvebarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE; + resolvebarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RESOLVE_DEST; ID3D12GraphicsCommandList *list = m_pDevice->GetNewList(); @@ -549,39 +582,77 @@ void D3D12Replay::FlipOutputWindow(uint64_t id) if(outw.multisampled) { // transition colour to resolve source, resolve target to resolve dest, backbuffer to copy dest - list->ResourceBarrier(3, barriers); + list->ResourceBarrier(1, &colbarrier); + list->ResourceBarrier(1, &resolvebarrier); + + if(bbbarrier.Transition.pResource) + list->ResourceBarrier(1, &bbbarrier); // resolve then copy, as the resolve can't go from SRGB to non-SRGB target - list->ResolveSubresource(barriers[2].Transition.pResource, 0, barriers[0].Transition.pResource, - 0, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB); + list->ResolveSubresource(outw.colResolve, 0, outw.col, 0, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB); - std::swap(barriers[2].Transition.StateBefore, barriers[2].Transition.StateAfter); + std::swap(resolvebarrier.Transition.StateBefore, resolvebarrier.Transition.StateAfter); // now move the resolve target into copy source - list->ResourceBarrier(1, &barriers[2]); + list->ResourceBarrier(1, &resolvebarrier); - list->CopyResource(barriers[1].Transition.pResource, barriers[2].Transition.pResource); + if(bbbarrier.Transition.pResource) + list->CopyResource(bbbarrier.Transition.pResource, resolvebarrier.Transition.pResource); } else { // transition colour to copy source, backbuffer to copy dest - list->ResourceBarrier(2, barriers); + list->ResourceBarrier(1, &colbarrier); - list->CopyResource(barriers[1].Transition.pResource, barriers[0].Transition.pResource); + if(bbbarrier.Transition.pResource) + list->ResourceBarrier(1, &bbbarrier); + + if(bbbarrier.Transition.pResource) + list->CopyResource(bbbarrier.Transition.pResource, colbarrier.Transition.pResource); } - std::swap(barriers[0].Transition.StateBefore, barriers[0].Transition.StateAfter); - std::swap(barriers[1].Transition.StateBefore, barriers[1].Transition.StateAfter); + std::swap(colbarrier.Transition.StateBefore, colbarrier.Transition.StateAfter); + std::swap(bbbarrier.Transition.StateBefore, bbbarrier.Transition.StateAfter); // transition colour back to render target, and backbuffer back to present - list->ResourceBarrier(2, barriers); + list->ResourceBarrier(1, &colbarrier); + + if(bbbarrier.Transition.pResource) + list->ResourceBarrier(1, &bbbarrier); + + if(m_D3D12On7) + { + ID3D12Resource *res = outw.multisampled ? outw.colResolve : outw.col; + + D3D12_RESOURCE_BARRIER toPresent = {}; + + toPresent.Transition.pResource = res; + toPresent.Transition.StateBefore = + outw.multisampled ? D3D12_RESOURCE_STATE_COPY_SOURCE : D3D12_RESOURCE_STATE_RENDER_TARGET; + toPresent.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; + + list->ResourceBarrier(1, &toPresent); + + ID3D12CommandQueueDownlevel *downlevel = NULL; + m_pDevice->GetQueue()->QueryInterface(__uuidof(ID3D12CommandQueueDownlevel), (void **)&downlevel); + downlevel->Present(list, res, outw.wnd, D3D12_DOWNLEVEL_PRESENT_FLAG_NONE); + SAFE_RELEASE(downlevel); + m_pDevice->MarkListExecuted((ID3D12GraphicsCommandList4 *)list); + + list = m_pDevice->GetNewList(); + + std::swap(toPresent.Transition.StateBefore, toPresent.Transition.StateAfter); + + list->ResourceBarrier(1, &toPresent); + } list->Close(); m_pDevice->ExecuteLists(); m_pDevice->FlushLists(); - outw.swap->Present(0, 0); + if(outw.swap) + outw.swap->Present(0, 0); outw.bbIdx++; outw.bbIdx %= 2; diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index 6f9837fc4..14ccc81a3 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -23,6 +23,7 @@ ******************************************************************************/ #include "d3d12_replay.h" +#include "core/plugins.h" #include "driver/dx/official/d3dcompiler.h" #include "driver/dxgi/dxgi_common.h" #include "driver/ihv/amd/amd_counters.h" @@ -108,7 +109,7 @@ void D3D12Replay::Initialise() PFN_CREATE_DXGI_FACTORY createFunc = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(GetModuleHandleA("dxgi.dll"), "CreateDXGIFactory1"); - HRESULT hr = createFunc(__uuidof(IDXGIFactory4), (void **)&m_pFactory); + HRESULT hr = createFunc(__uuidof(IDXGIFactory1), (void **)&m_pFactory); if(FAILED(hr)) { @@ -119,12 +120,12 @@ void D3D12Replay::Initialise() if(m_pFactory) { - RefCountDXGIObject::HandleWrap(__uuidof(IDXGIFactory4), (void **)&m_pFactory); + RefCountDXGIObject::HandleWrap(__uuidof(IDXGIFactory1), (void **)&m_pFactory); LUID luid = m_pDevice->GetAdapterLuid(); - IDXGIAdapter *pDXGIAdapter; - hr = m_pFactory->EnumAdapterByLuid(luid, __uuidof(IDXGIAdapter), (void **)&pDXGIAdapter); + IDXGIAdapter *pDXGIAdapter = NULL; + hr = EnumAdapterByLuid(m_pFactory, luid, &pDXGIAdapter); if(FAILED(hr)) { @@ -3586,12 +3587,47 @@ ReplayStatus D3D12_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver) WrappedIDXGISwapChain4::RegisterD3DDeviceCallback(GetD3D12DeviceIfAlloc); + bool d3d12on7 = false; + HMODULE lib = NULL; lib = LoadLibraryA("d3d12.dll"); if(lib == NULL) { - RDCERR("Failed to load d3d12.dll"); - return ReplayStatus::APIInitFailed; + // if it fails try to find D3D12On7 DLLs + d3d12on7 = true; + + // if it fails, try in the plugin directory + lib = (HMODULE)Process::LoadModule(LocatePluginFile("d3d12", "d3d12.dll").c_str()); + + // if that succeeded, also load dxilconv7.dll from there + if(lib) + { + HMODULE dxilconv = + (HMODULE)Process::LoadModule(LocatePluginFile("d3d12", "dxilconv7.dll").c_str()); + + if(!dxilconv) + { + RDCERR("Found d3d12.dll in plugin path, but couldn't load dxilconv7.dll"); + return ReplayStatus::APIInitFailed; + } + } + else + { + // if it failed, try one more time in MS's subfolder convention + lib = LoadLibraryA("12on7/d3d12.dll"); + + if(lib) + { + RDCWARN( + "Loaded d3d12.dll from 12on7 subfolder." + "Please use RenderDoc's plugins/d3d12/ subfolder instead"); + } + else + { + RDCERR("Failed to load d3d12.dll"); + return ReplayStatus::APIInitFailed; + } + } } PFN_D3D12_CREATE_DEVICE createDevice = @@ -3693,6 +3729,7 @@ ReplayStatus D3D12_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver) RDCLOG("Created device."); D3D12Replay *replay = wrappedDev->GetReplay(); + replay->Set12On7(d3d12on7); replay->SetProxy(rdc == NULL); replay->SetRGP(rgp); diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index 5a107240e..38826af38 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -55,6 +55,7 @@ public: D3D12DebugManager *GetDebugManager() { return m_DebugManager; } void SetRGP(AMDRGPControl *rgp) { m_RGP = rgp; } + void Set12On7(bool d3d12on7) { m_D3D12On7 = d3d12on7; } void SetProxy(bool proxy) { m_Proxy = proxy; } bool IsRemoteProxy() { return m_Proxy; } void Initialise(); @@ -288,7 +289,7 @@ private: ID3D12Resource *m_SOPatchedIndexBuffer = NULL; ID3D12QueryHeap *m_SOQueryHeap = NULL; - bool m_Proxy; + bool m_Proxy, m_D3D12On7; std::vector m_ProxyResources; @@ -303,6 +304,7 @@ private: ID3D12Resource *depth; D3D12_CPU_DESCRIPTOR_HANDLE rtv; D3D12_CPU_DESCRIPTOR_HANDLE dsv; + D3D12_RESOURCE_DESC bbDesc; WrappedID3D12Device *dev; @@ -419,7 +421,7 @@ private: D3D12DebugManager *m_DebugManager = NULL; - IDXGIFactory4 *m_pFactory = NULL; + IDXGIFactory1 *m_pFactory = NULL; AMDCounters *m_pAMDCounters = NULL; AMDRGPControl *m_RGP = NULL; diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj index 661961733..63f61deb3 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj @@ -137,6 +137,8 @@ + + diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters index 0909363fc..66ce61d42 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters @@ -69,6 +69,12 @@ Util + + official + + + official + diff --git a/renderdoc/driver/dx/official/D3D11On12On7.h b/renderdoc/driver/dx/official/D3D11On12On7.h new file mode 100644 index 000000000..751a0f3a9 --- /dev/null +++ b/renderdoc/driver/dx/official/D3D11On12On7.h @@ -0,0 +1,32 @@ +#pragma once + +// Just an identity interface, no functionality exposed, retrieved by ID3D11On12On7::GetThreadLastCreatedResource +interface ID3D11On12On7Resource { }; + +// Per-device, retrieved by ID3D11On12On7::GetThreadLastCreatedDevice +interface ID3D11On12On7Device +{ + // Equivalent to ID3D11On12Device::AcquireWrappedResources: + // From this point on, the resource should be used by D3D11, not by D3D12 directly. + STDMETHOD(AcquireResource)(ID3D11On12On7Resource* pResource, D3D12_RESOURCE_STATES state) = 0; + // Equivalent to ID3D11On12Device::ReleaseWrappedResources: + // Note that this cannot unbind the resource from D3D11, that is the app's responsibility. + // After calling this, the app should call Flush() on the D3D11 device. + STDMETHOD(ReleaseResource)(ID3D11On12On7Resource* pResource, D3D12_RESOURCE_STATES state) = 0; +}; + +// Global, retrieved by GetD3D11On12On7Interface +interface ID3D11On12On7 : public IUnknown +{ + // Enables usage similar to D3D11On12CreateDevice. + STDMETHOD_(void, SetThreadDeviceCreationParams)(ID3D12Device* pDevice, ID3D12CommandQueue* pGraphicsQueue) = 0; + // Enables usage similar to ID3D11On12Device::CreateWrappedResource. + // Note that the D3D11 resource creation parameters should be similar to the D3D12 resource, + // or else unexpected/undefined behavior may occur. + STDMETHOD_(void, SetThreadResourceCreationParams)(ID3D12Resource* pResource) = 0; + STDMETHOD_(ID3D11On12On7Device*, GetThreadLastCreatedDevice)() = 0; + STDMETHOD_(ID3D11On12On7Resource*, GetThreadLastCreatedResource)() = 0; +}; + +extern "C" HRESULT APIENTRY GetD3D11On12On7Interface(ID3D11On12On7** ppIface); +typedef HRESULT(APIENTRY *PFNGetD3D11On12On7Interface)(ID3D11On12On7** ppIface); \ No newline at end of file diff --git a/renderdoc/driver/dx/official/D3D12Downlevel.h b/renderdoc/driver/dx/official/D3D12Downlevel.h new file mode 100644 index 000000000..cb5a0a49a --- /dev/null +++ b/renderdoc/driver/dx/official/D3D12Downlevel.h @@ -0,0 +1,280 @@ +/*------------------------------------------------------------------------------------- + * + * Copyright (c) Microsoft Corporation + * + *-------------------------------------------------------------------------------------*/ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 8.01.0622 */ + + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 500 +#endif + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCSAL_H_VERSION__ +#define __REQUIRED_RPCSAL_H_VERSION__ 100 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif /* __RPCNDR_H_VERSION__ */ + +#ifndef COM_NO_WINDOWS_H +#include "windows.h" +#include "ole2.h" +#endif /*COM_NO_WINDOWS_H*/ + +#ifndef __d3d12downlevel_h__ +#define __d3d12downlevel_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifndef __ID3D12CommandQueueDownlevel_FWD_DEFINED__ +#define __ID3D12CommandQueueDownlevel_FWD_DEFINED__ +typedef interface ID3D12CommandQueueDownlevel ID3D12CommandQueueDownlevel; + +#endif /* __ID3D12CommandQueueDownlevel_FWD_DEFINED__ */ + + +#ifndef __ID3D12DeviceDownlevel_FWD_DEFINED__ +#define __ID3D12DeviceDownlevel_FWD_DEFINED__ +typedef interface ID3D12DeviceDownlevel ID3D12DeviceDownlevel; + +#endif /* __ID3D12DeviceDownlevel_FWD_DEFINED__ */ + + +/* header files for imported files */ +#include "oaidl.h" +#include "ocidl.h" +#include "d3d12.h" +#include "dxgi1_4.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +/* interface __MIDL_itf_d3d12downlevel_0000_0000 */ +/* [local] */ + +#include "winapifamily.h" +#pragma region Desktop Family +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +typedef +enum D3D12_DOWNLEVEL_PRESENT_FLAGS + { + D3D12_DOWNLEVEL_PRESENT_FLAG_NONE = 0, + D3D12_DOWNLEVEL_PRESENT_FLAG_WAIT_FOR_VBLANK = ( D3D12_DOWNLEVEL_PRESENT_FLAG_NONE + 1 ) + } D3D12_DOWNLEVEL_PRESENT_FLAGS; + +DEFINE_ENUM_FLAG_OPERATORS( D3D12_DOWNLEVEL_PRESENT_FLAGS ); + + +extern RPC_IF_HANDLE __MIDL_itf_d3d12downlevel_0000_0000_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_d3d12downlevel_0000_0000_v0_0_s_ifspec; + +#ifndef __ID3D12CommandQueueDownlevel_INTERFACE_DEFINED__ +#define __ID3D12CommandQueueDownlevel_INTERFACE_DEFINED__ + +/* interface ID3D12CommandQueueDownlevel */ +/* [unique][local][object][uuid] */ + + +EXTERN_C const IID IID_ID3D12CommandQueueDownlevel; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("38a8c5ef-7ccb-4e81-914f-a6e9d072c494") + ID3D12CommandQueueDownlevel : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Present( + _In_ ID3D12GraphicsCommandList *pOpenCommandList, + _In_ ID3D12Resource *pSourceTex2D, + _In_ HWND hWindow, + D3D12_DOWNLEVEL_PRESENT_FLAGS Flags) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ID3D12CommandQueueDownlevelVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ID3D12CommandQueueDownlevel * This, + REFIID riid, + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ID3D12CommandQueueDownlevel * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ID3D12CommandQueueDownlevel * This); + + HRESULT ( STDMETHODCALLTYPE *Present )( + ID3D12CommandQueueDownlevel * This, + _In_ ID3D12GraphicsCommandList *pOpenCommandList, + _In_ ID3D12Resource *pSourceTex2D, + _In_ HWND hWindow, + D3D12_DOWNLEVEL_PRESENT_FLAGS Flags); + + END_INTERFACE + } ID3D12CommandQueueDownlevelVtbl; + + interface ID3D12CommandQueueDownlevel + { + CONST_VTBL struct ID3D12CommandQueueDownlevelVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ID3D12CommandQueueDownlevel_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ID3D12CommandQueueDownlevel_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ID3D12CommandQueueDownlevel_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ID3D12CommandQueueDownlevel_Present(This,pOpenCommandList,pSourceTex2D,hWindow,Flags) \ + ( (This)->lpVtbl -> Present(This,pOpenCommandList,pSourceTex2D,hWindow,Flags) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ID3D12CommandQueueDownlevel_INTERFACE_DEFINED__ */ + + +#ifndef __ID3D12DeviceDownlevel_INTERFACE_DEFINED__ +#define __ID3D12DeviceDownlevel_INTERFACE_DEFINED__ + +/* interface ID3D12DeviceDownlevel */ +/* [unique][local][object][uuid] */ + + +EXTERN_C const IID IID_ID3D12DeviceDownlevel; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("74eaee3f-2f4b-476d-82ba-2b85cb49e310") + ID3D12DeviceDownlevel : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE QueryVideoMemoryInfo( + UINT NodeIndex, + DXGI_MEMORY_SEGMENT_GROUP MemorySegmentGroup, + _Out_ DXGI_QUERY_VIDEO_MEMORY_INFO *pVideoMemoryInfo) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ID3D12DeviceDownlevelVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ID3D12DeviceDownlevel * This, + REFIID riid, + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ID3D12DeviceDownlevel * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ID3D12DeviceDownlevel * This); + + HRESULT ( STDMETHODCALLTYPE *QueryVideoMemoryInfo )( + ID3D12DeviceDownlevel * This, + UINT NodeIndex, + DXGI_MEMORY_SEGMENT_GROUP MemorySegmentGroup, + _Out_ DXGI_QUERY_VIDEO_MEMORY_INFO *pVideoMemoryInfo); + + END_INTERFACE + } ID3D12DeviceDownlevelVtbl; + + interface ID3D12DeviceDownlevel + { + CONST_VTBL struct ID3D12DeviceDownlevelVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ID3D12DeviceDownlevel_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ID3D12DeviceDownlevel_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ID3D12DeviceDownlevel_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ID3D12DeviceDownlevel_QueryVideoMemoryInfo(This,NodeIndex,MemorySegmentGroup,pVideoMemoryInfo) \ + ( (This)->lpVtbl -> QueryVideoMemoryInfo(This,NodeIndex,MemorySegmentGroup,pVideoMemoryInfo) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ID3D12DeviceDownlevel_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_d3d12downlevel_0000_0002 */ +/* [local] */ + +#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */ +#pragma endregion +DEFINE_GUID(IID_ID3D12CommandQueueDownlevel,0x38a8c5ef,0x7ccb,0x4e81,0x91,0x4f,0xa6,0xe9,0xd0,0x72,0xc4,0x94); +DEFINE_GUID(IID_ID3D12DeviceDownlevel,0x74eaee3f,0x2f4b,0x476d,0x82,0xba,0x2b,0x85,0xcb,0x49,0xe3,0x10); + + +extern RPC_IF_HANDLE __MIDL_itf_d3d12downlevel_0000_0002_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_d3d12downlevel_0000_0002_v0_0_s_ifspec; + +/* Additional Prototypes for ALL interfaces */ + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/renderdoc/driver/dxgi/dxgi_wrapped.cpp b/renderdoc/driver/dxgi/dxgi_wrapped.cpp index 38303648e..a21fe6c56 100644 --- a/renderdoc/driver/dxgi/dxgi_wrapped.cpp +++ b/renderdoc/driver/dxgi/dxgi_wrapped.cpp @@ -473,7 +473,7 @@ HRESULT WrappedIDXGISwapChain4::GetBuffer( { DXGI_SWAP_CHAIN_DESC desc; GetDesc(&desc); - tex = m_pDevice->WrapSwapchainBuffer(this, &desc, Buffer, realSurface); + tex = m_pDevice->WrapSwapchainBuffer(this, desc.BufferDesc.Format, Buffer, realSurface); } // if the original UUID was IDXGISurface, fixup for the expected interface being returned @@ -534,6 +534,7 @@ HRESULT WrappedIDXGISwapChain4::Present( SyncInterval = 0; } + TickLastPresentedBuffer(); m_pDevice->Present(this, SyncInterval, Flags); return m_pReal->Present(SyncInterval, Flags); @@ -547,6 +548,7 @@ HRESULT WrappedIDXGISwapChain4::Present1(UINT SyncInterval, UINT Flags, SyncInterval = 0; } + TickLastPresentedBuffer(); m_pDevice->Present(this, SyncInterval, Flags); return m_pReal1->Present1(SyncInterval, Flags, pPresentParameters); diff --git a/renderdoc/driver/dxgi/dxgi_wrapped.h b/renderdoc/driver/dxgi/dxgi_wrapped.h index 86d5100d6..8d43f70f6 100644 --- a/renderdoc/driver/dxgi/dxgi_wrapped.h +++ b/renderdoc/driver/dxgi/dxgi_wrapped.h @@ -155,7 +155,19 @@ public: return RefCountDXGIObject::GetParent(riid, ppvObject); \ } -class WrappedIDXGISwapChain4; +struct ID3DDevice; + +struct IDXGISwapper +{ + virtual ID3DDevice *GetD3DDevice() = 0; + virtual int GetNumBackbuffers() = 0; + virtual IUnknown **GetBackbuffers() = 0; + virtual int GetLastPresentedBuffer() = 0; + virtual UINT GetWidth() = 0; + virtual UINT GetHeight() = 0; + virtual DXGI_FORMAT GetFormat() = 0; + virtual HWND GetHWND() = 0; +}; struct ID3DDevice { @@ -171,16 +183,16 @@ struct ID3DDevice virtual bool IsDeviceUUID(REFIID guid) = 0; virtual IUnknown *GetDeviceInterface(REFIID guid) = 0; - virtual void FirstFrame(WrappedIDXGISwapChain4 *swapChain) = 0; + virtual void FirstFrame(IDXGISwapper *swapper) = 0; virtual void NewSwapchainBuffer(IUnknown *backbuffer) = 0; - virtual void ReleaseSwapchainResources(WrappedIDXGISwapChain4 *swapChain, UINT QueueCount, + virtual void ReleaseSwapchainResources(IDXGISwapper *swapper, UINT QueueCount, IUnknown *const *ppPresentQueue, IUnknown **unwrappedQueues) = 0; - virtual IUnknown *WrapSwapchainBuffer(WrappedIDXGISwapChain4 *swap, DXGI_SWAP_CHAIN_DESC *swapDesc, + virtual IUnknown *WrapSwapchainBuffer(IDXGISwapper *swapper, DXGI_FORMAT bufferFormat, UINT buffer, IUnknown *realSurface) = 0; - virtual HRESULT Present(WrappedIDXGISwapChain4 *swapChain, UINT SyncInterval, UINT Flags) = 0; + virtual HRESULT Present(IDXGISwapper *swapper, UINT SyncInterval, UINT Flags) = 0; }; typedef ID3DDevice *(*D3DDeviceCallback)(IUnknown *dev); @@ -545,7 +557,7 @@ public: } }; -class WrappedIDXGISwapChain4 : public IDXGISwapChain4, public RefCountDXGIObject +class WrappedIDXGISwapChain4 : public IDXGISwapChain4, public RefCountDXGIObject, public IDXGISwapper { IDXGISwapChain *m_pReal; IDXGISwapChain1 *m_pReal1; @@ -561,11 +573,31 @@ class WrappedIDXGISwapChain4 : public IDXGISwapChain4, public RefCountDXGIObject static const int MAX_NUM_BACKBUFFERS = 8; IUnknown *m_pBackBuffers[MAX_NUM_BACKBUFFERS]; + int32_t m_LastPresentedBuffer = -1; void ReleaseBuffersForResize(UINT QueueCount, IUnknown *const *ppPresentQueue, IUnknown **unwrappedQueues); void WrapBuffersAfterResize(); + void TickLastPresentedBuffer() + { + DXGI_SWAP_CHAIN_DESC desc = {}; + + m_pReal->GetDesc(&desc); + + if(desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD) + { + // discard always presents from 0 + m_LastPresentedBuffer = 0; + } + else + { + // other modes use each buffer in turn + m_LastPresentedBuffer++; + m_LastPresentedBuffer %= desc.BufferCount; + } + } + public: WrappedIDXGISwapChain4(IDXGISwapChain *real, HWND wnd, ID3DDevice *device); virtual ~WrappedIDXGISwapChain4(); @@ -591,19 +623,47 @@ public: ID3DDevice *GetD3DDevice() { return m_pDevice; } int GetNumBackbuffers() { return MAX_NUM_BACKBUFFERS; } IUnknown **GetBackbuffers() { return m_pBackBuffers; } + int GetLastPresentedBuffer() { return RDCMAX(m_LastPresentedBuffer, 0); } IMPLEMENT_IDXGIOBJECT_WITH_REFCOUNTDXGIOBJECT_CUSTOMQUERY; HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); - DXGI_SWAP_CHAIN_DESC GetDescWithHWND() + HWND GetHWND() { - DXGI_SWAP_CHAIN_DESC ret = {}; + DXGI_SWAP_CHAIN_DESC desc = {}; - m_pReal->GetDesc(&ret); + m_pReal->GetDesc(&desc); - if(ret.OutputWindow == NULL) - ret.OutputWindow = m_Wnd; + if(desc.OutputWindow != NULL) + return desc.OutputWindow; - return ret; + return m_Wnd; + } + + UINT GetWidth() + { + DXGI_SWAP_CHAIN_DESC desc = {}; + + m_pReal->GetDesc(&desc); + + return desc.BufferDesc.Width; + } + + UINT GetHeight() + { + DXGI_SWAP_CHAIN_DESC desc = {}; + + m_pReal->GetDesc(&desc); + + return desc.BufferDesc.Height; + } + + DXGI_FORMAT GetFormat() + { + DXGI_SWAP_CHAIN_DESC desc = {}; + + m_pReal->GetDesc(&desc); + + return desc.BufferDesc.Format; } //////////////////////////////