mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-05 14:21:10 +00:00
390 lines
15 KiB
C++
390 lines
15 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2019-2021 Baldur Karlsson
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
#pragma once
|
|
|
|
#include "common/wrapped_pool.h"
|
|
#include "d3d12_commands.h"
|
|
#include "d3d12_common.h"
|
|
#include "d3d12_device.h"
|
|
#include "d3d12_resources.h"
|
|
|
|
class WrappedID3D12CommandQueue;
|
|
|
|
// this aren't documented, they're defined in D3D12TranslationLayer in the d3d11on12 codebase
|
|
MIDL_INTERFACE("7974c836-9520-4cda-8d43-d996622e8926")
|
|
ID3D12CompatibilityQueue : public IUnknown
|
|
{
|
|
public:
|
|
virtual HRESULT STDMETHODCALLTYPE AcquireKeyedMutex(
|
|
_In_ ID3D12Object * pHeapOrResourceWithKeyedMutex, UINT64 Key, DWORD dwTimeout,
|
|
_Reserved_ void *pReserved, _In_range_(0, 0) UINT Reserved) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE ReleaseKeyedMutex(
|
|
_In_ ID3D12Object * pHeapOrResourceWithKeyedMutex, UINT64 Key, _Reserved_ void *pReserved,
|
|
_In_range_(0, 0) UINT Reserved) = 0;
|
|
};
|
|
|
|
struct WrappedID3D12CompatibilityQueue : public ID3D12CompatibilityQueue
|
|
{
|
|
WrappedID3D12CommandQueue &m_pQueue;
|
|
ID3D12CompatibilityQueue *m_pReal = NULL;
|
|
|
|
WrappedID3D12CompatibilityQueue(WrappedID3D12CommandQueue &dev) : m_pQueue(dev) {}
|
|
//////////////////////////////
|
|
// implement IUnknown
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
|
|
ULONG STDMETHODCALLTYPE AddRef();
|
|
ULONG STDMETHODCALLTYPE Release();
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12CompatibilityQueue
|
|
virtual HRESULT STDMETHODCALLTYPE AcquireKeyedMutex(_In_ ID3D12Object *pHeapOrResourceWithKeyedMutex,
|
|
UINT64 Key, DWORD dwTimeout,
|
|
_Reserved_ void *pReserved,
|
|
_In_range_(0, 0) UINT Reserved);
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE ReleaseKeyedMutex(_In_ ID3D12Object *pHeapOrResourceWithKeyedMutex,
|
|
UINT64 Key, _Reserved_ void *pReserved,
|
|
_In_range_(0, 0) UINT Reserved);
|
|
};
|
|
|
|
struct WrappedID3D12DebugCommandQueue : public ID3D12DebugCommandQueue
|
|
{
|
|
WrappedID3D12CommandQueue *m_pQueue;
|
|
ID3D12DebugCommandQueue *m_pReal;
|
|
|
|
WrappedID3D12DebugCommandQueue() : m_pQueue(NULL), m_pReal(NULL) {}
|
|
//////////////////////////////
|
|
// implement IUnknown
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
|
|
{
|
|
if(riid == __uuidof(ID3D12DebugCommandQueue))
|
|
{
|
|
*ppvObject = (ID3D12DebugCommandQueue *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE AddRef();
|
|
ULONG STDMETHODCALLTYPE Release();
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12DebugCommandQueue
|
|
|
|
virtual BOOL STDMETHODCALLTYPE AssertResourceState(ID3D12Resource *pResource, UINT Subresource,
|
|
UINT State)
|
|
{
|
|
if(m_pReal)
|
|
return m_pReal->AssertResourceState(Unwrap(pResource), Subresource, State);
|
|
return TRUE;
|
|
}
|
|
};
|
|
|
|
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<ID3D12CommandQueue>,
|
|
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, *m_CreationRecord;
|
|
|
|
CaptureState &m_State;
|
|
|
|
bool m_MarkedActive = false;
|
|
|
|
ReplayStatus m_FailedReplayStatus = ReplayStatus::APIReplayFailed;
|
|
|
|
WrappedID3D12DebugCommandQueue m_WrappedDebug;
|
|
WrappedID3D12CompatibilityQueue m_WrappedCompat;
|
|
|
|
rdcarray<D3D12ResourceRecord *> m_CmdListRecords;
|
|
|
|
std::unordered_set<ResourceId> m_SparseBindResources;
|
|
|
|
// D3D12 guarantees that queues are thread-safe
|
|
Threading::CriticalSection m_Lock;
|
|
|
|
std::set<rdcstr> m_StringDB;
|
|
|
|
WriteSerialiser &GetThreadSerialiser();
|
|
|
|
StreamReader *m_FrameReader = NULL;
|
|
|
|
uint64_t m_TimeBase = 0;
|
|
double m_TimeFrequency = 1.0f;
|
|
SDFile *m_StructuredFile = NULL;
|
|
|
|
// command recording/replay data shared between queues and lists
|
|
D3D12CommandData m_Cmd;
|
|
|
|
ResourceId m_PrevQueueId;
|
|
|
|
bool ProcessChunk(ReadSerialiser &ser, D3D12Chunk context);
|
|
|
|
static rdcstr GetChunkName(uint32_t idx);
|
|
D3D12ResourceManager *GetResourceManager() { return m_pDevice->GetResourceManager(); }
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12CommandQueue);
|
|
|
|
WrappedID3D12CommandQueue(ID3D12CommandQueue *real, WrappedID3D12Device *device,
|
|
CaptureState &state);
|
|
virtual ~WrappedID3D12CommandQueue();
|
|
|
|
ResourceId GetResourceID() { return m_ResourceID; }
|
|
ID3D12CommandQueue *GetReal() { return m_pReal; }
|
|
D3D12ResourceRecord *GetResourceRecord() { return m_QueueRecord; }
|
|
D3D12ResourceRecord *GetCreationRecord() { return m_CreationRecord; }
|
|
WrappedID3D12Device *GetWrappedDevice() { return m_pDevice; }
|
|
const rdcarray<D3D12ResourceRecord *> &GetCmdLists() { return m_CmdListRecords; }
|
|
D3D12DrawcallTreeNode &GetParentDrawcall() { return m_Cmd.m_ParentDrawcall; }
|
|
const APIEvent &GetEvent(uint32_t eventId);
|
|
uint32_t GetMaxEID() { return m_Cmd.m_Events.back().eventId; }
|
|
void ClearAfterCapture();
|
|
|
|
bool IsSparseUpdatedResource(ResourceId id) const
|
|
{
|
|
return m_SparseBindResources.find(id) != m_SparseBindResources.end();
|
|
}
|
|
|
|
ReplayStatus ReplayLog(CaptureState readType, uint32_t startEventID, uint32_t endEventID,
|
|
bool partial);
|
|
void SetFrameReader(StreamReader *reader) { m_FrameReader = reader; }
|
|
D3D12CommandData *GetCommandData() { return &m_Cmd; }
|
|
const rdcarray<EventUsage> &GetUsage(ResourceId id) { return m_Cmd.m_ResourceUses[id]; }
|
|
// interface for DXGI
|
|
virtual IUnknown *GetRealIUnknown() { return GetReal(); }
|
|
virtual IID GetBackbufferUUID() { return __uuidof(ID3D12Resource); }
|
|
virtual bool IsDeviceUUID(REFIID iid)
|
|
{
|
|
return iid == __uuidof(ID3D12CommandQueue) ? true : false;
|
|
}
|
|
virtual IUnknown *GetDeviceInterface(REFIID iid)
|
|
{
|
|
if(iid == __uuidof(ID3D12CommandQueue))
|
|
return (ID3D12CommandQueue *)this;
|
|
|
|
RDCERR("Requested unknown device interface %s", ToStr(iid).c_str());
|
|
|
|
return NULL;
|
|
}
|
|
// the rest forward to the device
|
|
virtual void *GetFrameCapturerDevice() { return m_pDevice->GetFrameCapturerDevice(); }
|
|
virtual IFrameCapturer *GetFrameCapturer() { return m_pDevice->GetFrameCapturer(); }
|
|
virtual void FirstFrame(IDXGISwapper *swapper) { m_pDevice->FirstFrame(swapper); }
|
|
virtual void NewSwapchainBuffer(IUnknown *backbuffer)
|
|
{
|
|
m_pDevice->NewSwapchainBuffer(backbuffer);
|
|
}
|
|
virtual void ReleaseSwapchainResources(IDXGISwapper *swapper, UINT QueueCount,
|
|
IUnknown *const *ppPresentQueue, IUnknown **unwrappedQueues)
|
|
{
|
|
m_pDevice->ReleaseSwapchainResources(swapper, QueueCount, ppPresentQueue, unwrappedQueues);
|
|
}
|
|
virtual IUnknown *WrapSwapchainBuffer(IDXGISwapper *swapper, DXGI_FORMAT bufferFormat,
|
|
UINT buffer, IUnknown *realSurface)
|
|
{
|
|
return m_pDevice->WrapSwapchainBuffer(swapper, bufferFormat, buffer, realSurface);
|
|
}
|
|
virtual IDXGIResource *WrapExternalDXGIResource(IDXGIResource *res)
|
|
{
|
|
return m_pDevice->WrapExternalDXGIResource(res);
|
|
}
|
|
|
|
virtual HRESULT Present(IDXGISwapper *swapper, UINT SyncInterval, UINT 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
|
|
|
|
ULONG STDMETHODCALLTYPE AddRef() { return RefCounter12::SoftRef(m_pDevice); }
|
|
ULONG STDMETHODCALLTYPE Release() { return RefCounter12::SoftRelease(m_pDevice); }
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12Object
|
|
|
|
HRESULT STDMETHODCALLTYPE GetPrivateData(REFGUID guid, UINT *pDataSize, void *pData)
|
|
{
|
|
return m_pReal->GetPrivateData(guid, pDataSize, pData);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE SetPrivateData(REFGUID guid, UINT DataSize, const void *pData)
|
|
{
|
|
if(guid == WKPDID_D3DDebugObjectName)
|
|
{
|
|
m_pDevice->SetName(this, (const char *)pData);
|
|
}
|
|
else if(guid == WKPDID_D3DDebugObjectNameW)
|
|
{
|
|
rdcwstr wName((const wchar_t *)pData, DataSize / 2);
|
|
rdcstr sName = StringFormat::Wide2UTF8(wName);
|
|
m_pDevice->SetName(this, sName.c_str());
|
|
}
|
|
|
|
return m_pReal->SetPrivateData(guid, DataSize, pData);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(REFGUID guid, const IUnknown *pData)
|
|
{
|
|
return m_pReal->SetPrivateDataInterface(guid, pData);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE SetName(LPCWSTR Name)
|
|
{
|
|
rdcstr utf8 = StringFormat::Wide2UTF8(Name);
|
|
m_pDevice->SetName(this, utf8.c_str());
|
|
|
|
return m_pReal->SetName(Name);
|
|
}
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12DeviceChild
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetDevice(REFIID riid, _COM_Outptr_opt_ void **ppvDevice)
|
|
{
|
|
return m_pDevice->GetDevice(riid, ppvDevice);
|
|
}
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12CommandQueue
|
|
|
|
IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, UpdateTileMappings,
|
|
ID3D12Resource *pResource, UINT NumResourceRegions,
|
|
const D3D12_TILED_RESOURCE_COORDINATE *pResourceRegionStartCoordinates,
|
|
const D3D12_TILE_REGION_SIZE *pResourceRegionSizes, ID3D12Heap *pHeap,
|
|
UINT NumRanges, const D3D12_TILE_RANGE_FLAGS *pRangeFlags,
|
|
const UINT *pHeapRangeStartOffsets, const UINT *pRangeTileCounts,
|
|
D3D12_TILE_MAPPING_FLAGS Flags);
|
|
|
|
IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, CopyTileMappings,
|
|
ID3D12Resource *pDstResource,
|
|
const D3D12_TILED_RESOURCE_COORDINATE *pDstRegionStartCoordinate,
|
|
ID3D12Resource *pSrcResource,
|
|
const D3D12_TILED_RESOURCE_COORDINATE *pSrcRegionStartCoordinate,
|
|
const D3D12_TILE_REGION_SIZE *pRegionSize,
|
|
D3D12_TILE_MAPPING_FLAGS Flags);
|
|
|
|
IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, ExecuteCommandLists,
|
|
UINT NumCommandLists, ID3D12CommandList *const *ppCommandLists);
|
|
|
|
virtual void ExecuteCommandListsInternal(UINT NumCommandLists,
|
|
ID3D12CommandList *const *ppCommandLists,
|
|
bool InFrameCaptureBoundary, bool SkipRealExecute);
|
|
|
|
IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, SetMarker, UINT Metadata,
|
|
const void *pData, UINT Size);
|
|
|
|
IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, BeginEvent, UINT Metadata,
|
|
const void *pData, UINT Size);
|
|
|
|
IMPLEMENT_FUNCTION_SERIALISED(virtual void STDMETHODCALLTYPE, EndEvent, );
|
|
|
|
IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, Signal, ID3D12Fence *pFence,
|
|
UINT64 Value);
|
|
|
|
IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, Wait, ID3D12Fence *pFence,
|
|
UINT64 Value);
|
|
|
|
IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, GetTimestampFrequency,
|
|
UINT64 *pFrequency);
|
|
|
|
IMPLEMENT_FUNCTION_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, GetClockCalibration,
|
|
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 <>
|
|
ID3D12CommandQueue *Unwrap(ID3D12CommandQueue *obj);
|
|
|
|
template <>
|
|
ResourceId GetResID(ID3D12CommandQueue *obj);
|
|
|
|
template <>
|
|
D3D12ResourceRecord *GetRecord(ID3D12CommandQueue *obj);
|