mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-29 13:20:54 +00:00
cc3b2f6443
* This will be needed for copies where the size may not be known on the CPU - currently for AS builds we know the size directly. * We also only store the size of an AS not the whole pre-build info since we don't need the scratch data and it won't be available in full for copies.
1700 lines
53 KiB
C++
1700 lines
53 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2019-2024 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 "driver/shaders/dxbc/dxbc_container.h"
|
|
#include "serialise/serialiser.h"
|
|
#include "d3d12_device.h"
|
|
#include "d3d12_manager.h"
|
|
|
|
rdcpair<uint32_t, uint32_t> FindMatchingRootParameter(const D3D12RootSignature *sig,
|
|
D3D12_SHADER_VISIBILITY visibility,
|
|
D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
|
|
uint32_t space, uint32_t bind);
|
|
UINT GetPlaneForSubresource(ID3D12Resource *res, int Subresource);
|
|
UINT GetMipForSubresource(ID3D12Resource *res, int Subresource);
|
|
UINT GetSliceForSubresource(ID3D12Resource *res, int Subresource);
|
|
UINT GetMipForDsv(const D3D12_DEPTH_STENCIL_VIEW_DESC &dsv);
|
|
UINT GetSliceForDsv(const D3D12_DEPTH_STENCIL_VIEW_DESC &dsv);
|
|
UINT GetMipForRtv(const D3D12_RENDER_TARGET_VIEW_DESC &rtv);
|
|
UINT GetSliceForRtv(const D3D12_RENDER_TARGET_VIEW_DESC &rtv);
|
|
|
|
D3D12_SHADER_RESOURCE_VIEW_DESC MakeSRVDesc(const D3D12_RESOURCE_DESC &desc);
|
|
D3D12_UNORDERED_ACCESS_VIEW_DESC MakeUAVDesc(const D3D12_RESOURCE_DESC &desc);
|
|
|
|
class TrackedResource12
|
|
{
|
|
public:
|
|
TrackedResource12()
|
|
{
|
|
m_ID = ResourceIDGen::GetNewUniqueID();
|
|
m_pRecord = NULL;
|
|
}
|
|
ResourceId GetResourceID() { return m_ID; }
|
|
D3D12ResourceRecord *GetResourceRecord() { return m_pRecord; }
|
|
void SetResourceRecord(D3D12ResourceRecord *record) { m_pRecord = record; }
|
|
protected:
|
|
TrackedResource12(const TrackedResource12 &);
|
|
TrackedResource12 &operator=(const TrackedResource12 &);
|
|
|
|
ResourceId m_ID;
|
|
D3D12ResourceRecord *m_pRecord;
|
|
};
|
|
|
|
extern const GUID RENDERDOC_ID3D12ShaderGUID_ShaderDebugMagicValue;
|
|
|
|
template <typename NestedType, typename NestedType1 = NestedType, typename NestedType2 = NestedType1>
|
|
class WrappedDeviceChild12 : public RefCounter12<NestedType>,
|
|
public NestedType2,
|
|
public TrackedResource12
|
|
{
|
|
protected:
|
|
WrappedID3D12Device *m_pDevice;
|
|
int32_t m_Resident = 1;
|
|
|
|
WrappedDeviceChild12(NestedType *real, WrappedID3D12Device *device)
|
|
: RefCounter12(real), m_pDevice(device)
|
|
{
|
|
m_pDevice->SoftRef();
|
|
|
|
if(real)
|
|
{
|
|
bool ret = m_pDevice->GetResourceManager()->AddWrapper(this, real);
|
|
if(!ret)
|
|
RDCERR("Error adding wrapper for type %s", ToStr(__uuidof(NestedType)).c_str());
|
|
}
|
|
|
|
m_pDevice->GetResourceManager()->AddCurrentResource(GetResourceID(), this);
|
|
}
|
|
|
|
void Shutdown()
|
|
{
|
|
if(m_pReal)
|
|
m_pDevice->GetResourceManager()->RemoveWrapper(m_pReal);
|
|
|
|
m_pDevice->GetResourceManager()->ReleaseCurrentResource(GetResourceID());
|
|
m_pDevice->ReleaseResource((NestedType *)this);
|
|
SAFE_RELEASE(m_pReal);
|
|
m_pDevice = NULL;
|
|
}
|
|
|
|
virtual ~WrappedDeviceChild12()
|
|
{
|
|
// should have already called shutdown (needs to be called from child class to ensure
|
|
// vtables are still in place when we call ReleaseResource)
|
|
RDCASSERT(m_pDevice == NULL && m_pReal == NULL);
|
|
}
|
|
|
|
public:
|
|
typedef NestedType InnerType;
|
|
|
|
bool IsResident() { return m_Resident > 0; }
|
|
void MakeResident() { Atomic::Inc32(&m_Resident); }
|
|
void Evict() { Atomic::Dec32(&m_Resident); }
|
|
NestedType *GetReal() { return m_pReal; }
|
|
ULONG STDMETHODCALLTYPE AddRef() { return RefCounter12::SoftRef(m_pDevice); }
|
|
ULONG STDMETHODCALLTYPE Release() { return RefCounter12::SoftRelease(m_pDevice); }
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
|
|
{
|
|
if(riid == __uuidof(IUnknown))
|
|
{
|
|
*ppvObject = (IUnknown *)(NestedType *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else if(riid == __uuidof(NestedType))
|
|
{
|
|
*ppvObject = (NestedType *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else if(riid == __uuidof(NestedType1))
|
|
{
|
|
if(!m_pReal)
|
|
return E_NOINTERFACE;
|
|
|
|
// check that the real interface supports this
|
|
NestedType1 *dummy = NULL;
|
|
HRESULT check = m_pReal->QueryInterface(riid, (void **)&dummy);
|
|
|
|
SAFE_RELEASE(dummy);
|
|
|
|
if(FAILED(check))
|
|
return check;
|
|
|
|
*ppvObject = (NestedType1 *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else if(riid == __uuidof(NestedType2))
|
|
{
|
|
if(!m_pReal)
|
|
return E_NOINTERFACE;
|
|
|
|
// check that the real interface supports this
|
|
NestedType2 *dummy = NULL;
|
|
HRESULT check = m_pReal->QueryInterface(riid, (void **)&dummy);
|
|
|
|
SAFE_RELEASE(dummy);
|
|
|
|
if(FAILED(check))
|
|
return check;
|
|
|
|
*ppvObject = (NestedType2 *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else if(riid == __uuidof(ID3D12Pageable))
|
|
{
|
|
// not all child classes support this, so check it on the real interface
|
|
if(!m_pReal)
|
|
return E_NOINTERFACE;
|
|
|
|
// check that the real interface supports this
|
|
ID3D12Pageable *dummy = NULL;
|
|
HRESULT check = m_pReal->QueryInterface(riid, (void **)&dummy);
|
|
|
|
SAFE_RELEASE(dummy);
|
|
|
|
if(FAILED(check))
|
|
return check;
|
|
|
|
*ppvObject = (ID3D12Pageable *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else if(riid == __uuidof(ID3D12Object))
|
|
{
|
|
*ppvObject = (ID3D12DeviceChild *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else if(riid == __uuidof(ID3D12DeviceChild))
|
|
{
|
|
*ppvObject = (ID3D12DeviceChild *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
// for DXGI object queries, just make a new throw-away WrappedDXGIObject
|
|
// and return.
|
|
if(riid == __uuidof(IDXGIObject) || riid == __uuidof(IDXGIDeviceSubObject) ||
|
|
riid == __uuidof(IDXGIResource) || riid == __uuidof(IDXGIKeyedMutex) ||
|
|
riid == __uuidof(IDXGISurface) || riid == __uuidof(IDXGISurface1) ||
|
|
riid == __uuidof(IDXGIResource1) || riid == __uuidof(IDXGISurface2))
|
|
{
|
|
if(m_pReal == NULL)
|
|
return E_NOINTERFACE;
|
|
|
|
// ensure the real object has this interface
|
|
void *outObj;
|
|
HRESULT hr = m_pReal->QueryInterface(riid, &outObj);
|
|
|
|
IUnknown *unk = (IUnknown *)outObj;
|
|
SAFE_RELEASE(unk);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
auto dxgiWrapper = new WrappedDXGIInterface<WrappedDeviceChild12>(this, m_pDevice);
|
|
|
|
// anything could happen outside of our wrapped ecosystem, so immediately mark dirty
|
|
m_pDevice->GetResourceManager()->MarkDirtyResource(GetResourceID());
|
|
|
|
if(riid == __uuidof(IDXGIObject))
|
|
{
|
|
*ppvObject = (IDXGIObject *)(IDXGIKeyedMutex *)dxgiWrapper;
|
|
}
|
|
else if(riid == __uuidof(IDXGIDeviceSubObject))
|
|
{
|
|
*ppvObject = (IDXGIDeviceSubObject *)(IDXGIKeyedMutex *)dxgiWrapper;
|
|
}
|
|
else if(riid == __uuidof(IDXGIResource))
|
|
{
|
|
*ppvObject = (IDXGIResource *)dxgiWrapper;
|
|
}
|
|
else if(riid == __uuidof(IDXGIKeyedMutex))
|
|
{
|
|
*ppvObject = (IDXGIKeyedMutex *)dxgiWrapper;
|
|
}
|
|
else if(riid == __uuidof(IDXGISurface))
|
|
{
|
|
*ppvObject = (IDXGISurface *)dxgiWrapper;
|
|
}
|
|
else if(riid == __uuidof(IDXGISurface1))
|
|
{
|
|
*ppvObject = (IDXGISurface1 *)dxgiWrapper;
|
|
}
|
|
else if(riid == __uuidof(IDXGIResource1))
|
|
{
|
|
*ppvObject = (IDXGIResource1 *)dxgiWrapper;
|
|
}
|
|
else if(riid == __uuidof(IDXGISurface2))
|
|
{
|
|
*ppvObject = (IDXGISurface2 *)dxgiWrapper;
|
|
}
|
|
else
|
|
{
|
|
RDCWARN("Unexpected guid %s", ToStr(riid).c_str());
|
|
SAFE_DELETE(dxgiWrapper);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
return RefCounter12::QueryInterface("ID3D12DeviceChild", riid, ppvObject);
|
|
}
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12Object
|
|
|
|
HRESULT STDMETHODCALLTYPE GetPrivateData(REFGUID guid, UINT *pDataSize, void *pData)
|
|
{
|
|
if(!m_pReal)
|
|
{
|
|
if(pDataSize)
|
|
*pDataSize = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
return m_pReal->GetPrivateData(guid, pDataSize, pData);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE SetPrivateData(REFGUID guid, UINT DataSize, const void *pData)
|
|
{
|
|
if(guid == RENDERDOC_ID3D12ShaderGUID_ShaderDebugMagicValue)
|
|
return m_pDevice->SetShaderDebugPath(this, (const char *)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());
|
|
}
|
|
|
|
if(!m_pReal)
|
|
return S_OK;
|
|
|
|
return m_pReal->SetPrivateData(guid, DataSize, pData);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(REFGUID guid, const IUnknown *pData)
|
|
{
|
|
if(!m_pReal)
|
|
return S_OK;
|
|
|
|
return m_pReal->SetPrivateDataInterface(guid, pData);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE SetName(LPCWSTR Name)
|
|
{
|
|
rdcstr utf8 = Name ? StringFormat::Wide2UTF8(Name) : "";
|
|
m_pDevice->SetName(this, utf8.c_str());
|
|
|
|
if(!m_pReal)
|
|
return S_OK;
|
|
|
|
return m_pReal->SetName(Name);
|
|
}
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12DeviceChild
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetDevice(REFIID riid, _COM_Outptr_opt_ void **ppvDevice)
|
|
{
|
|
return m_pDevice->GetDevice(riid, ppvDevice);
|
|
}
|
|
};
|
|
|
|
class WrappedID3D12CommandAllocator : public WrappedDeviceChild12<ID3D12CommandAllocator>
|
|
{
|
|
static int32_t m_ResetEnabled;
|
|
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12CommandAllocator);
|
|
|
|
bool m_Internal = false;
|
|
|
|
enum
|
|
{
|
|
TypeEnum = Resource_CommandAllocator,
|
|
};
|
|
|
|
WrappedID3D12CommandAllocator(ID3D12CommandAllocator *real, WrappedID3D12Device *device)
|
|
: WrappedDeviceChild12(real, device)
|
|
{
|
|
}
|
|
virtual ~WrappedID3D12CommandAllocator() { Shutdown(); }
|
|
static void PauseResets() { Atomic::Dec32(&m_ResetEnabled); }
|
|
static void ResumeResets() { Atomic::Inc32(&m_ResetEnabled); }
|
|
//////////////////////////////
|
|
// implement ID3D12CommandAllocator
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE Reset()
|
|
{
|
|
// reset the allocator. D3D12 munges the pool and the allocator together, so the allocator
|
|
// becomes redundant as the only pool client and the pool is reset together.
|
|
if(Atomic::CmpExch32(&m_ResetEnabled, 1, 1) == 1 && m_pRecord && m_pRecord->cmdInfo->alloc)
|
|
m_pRecord->cmdInfo->alloc->Reset();
|
|
return m_pReal->Reset();
|
|
}
|
|
};
|
|
|
|
class WrappedID3D12CommandSignature : public WrappedDeviceChild12<ID3D12CommandSignature>
|
|
{
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12CommandSignature);
|
|
|
|
D3D12CommandSignature sig;
|
|
|
|
enum
|
|
{
|
|
TypeEnum = Resource_CommandSignature,
|
|
};
|
|
|
|
WrappedID3D12CommandSignature(ID3D12CommandSignature *real, WrappedID3D12Device *device)
|
|
: WrappedDeviceChild12(real, device)
|
|
{
|
|
}
|
|
virtual ~WrappedID3D12CommandSignature() { Shutdown(); }
|
|
};
|
|
|
|
struct D3D12Descriptor;
|
|
|
|
class WrappedID3D12DescriptorHeap : public WrappedDeviceChild12<ID3D12DescriptorHeap>
|
|
{
|
|
D3D12_CPU_DESCRIPTOR_HANDLE realCPUBase;
|
|
D3D12_GPU_DESCRIPTOR_HANDLE realGPUBase;
|
|
|
|
UINT increment;
|
|
UINT numDescriptors;
|
|
|
|
D3D12Descriptor *descriptors;
|
|
|
|
Descriptor *cachedDescriptors;
|
|
uint64_t *mutableDescriptorBitmask;
|
|
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12DescriptorHeap);
|
|
|
|
enum
|
|
{
|
|
TypeEnum = Resource_DescriptorHeap,
|
|
};
|
|
|
|
WrappedID3D12DescriptorHeap(ID3D12DescriptorHeap *real, WrappedID3D12Device *device,
|
|
const D3D12_DESCRIPTOR_HEAP_DESC &desc, UINT UnpatchedNumDescriptors);
|
|
virtual ~WrappedID3D12DescriptorHeap();
|
|
|
|
D3D12Descriptor *GetDescriptors() { return descriptors; }
|
|
UINT GetNumDescriptors() { return numDescriptors; }
|
|
|
|
void MarkMutableIndex(uint32_t index);
|
|
|
|
void EnsureDescriptorCache();
|
|
bool HasValidDescriptorCache(uint32_t index);
|
|
void GetFromDescriptorCache(uint32_t index, Descriptor &view);
|
|
void SetToDescriptorCache(uint32_t index, const Descriptor &view);
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12DescriptorHeap
|
|
|
|
virtual D3D12_DESCRIPTOR_HEAP_DESC STDMETHODCALLTYPE GetDesc() { return m_pReal->GetDesc(); }
|
|
virtual D3D12_CPU_DESCRIPTOR_HANDLE STDMETHODCALLTYPE GetCPUDescriptorHandleForHeapStart()
|
|
{
|
|
D3D12_CPU_DESCRIPTOR_HANDLE handle;
|
|
handle.ptr = (SIZE_T)descriptors;
|
|
return handle;
|
|
}
|
|
|
|
virtual D3D12_GPU_DESCRIPTOR_HANDLE STDMETHODCALLTYPE GetGPUDescriptorHandleForHeapStart()
|
|
{
|
|
D3D12_GPU_DESCRIPTOR_HANDLE handle;
|
|
handle.ptr = (UINT64)descriptors;
|
|
return handle;
|
|
}
|
|
|
|
D3D12_CPU_DESCRIPTOR_HANDLE GetCPU(uint32_t idx)
|
|
{
|
|
D3D12_CPU_DESCRIPTOR_HANDLE handle = realCPUBase;
|
|
handle.ptr += idx * increment;
|
|
return handle;
|
|
}
|
|
|
|
D3D12_GPU_DESCRIPTOR_HANDLE GetGPU(uint32_t idx)
|
|
{
|
|
D3D12_GPU_DESCRIPTOR_HANDLE handle = realGPUBase;
|
|
handle.ptr += idx * increment;
|
|
return handle;
|
|
}
|
|
|
|
uint32_t GetUnwrappedIncrement() const { return increment; }
|
|
};
|
|
|
|
class WrappedID3D12Fence : public WrappedDeviceChild12<ID3D12Fence, ID3D12Fence1>
|
|
{
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12Fence);
|
|
|
|
enum
|
|
{
|
|
TypeEnum = Resource_Fence,
|
|
};
|
|
|
|
WrappedID3D12Fence(ID3D12Fence *real, WrappedID3D12Device *device)
|
|
: WrappedDeviceChild12(real, device)
|
|
{
|
|
}
|
|
virtual ~WrappedID3D12Fence() { Shutdown(); }
|
|
//////////////////////////////
|
|
// implement ID3D12Fence
|
|
|
|
virtual UINT64 STDMETHODCALLTYPE GetCompletedValue() { return m_pReal->GetCompletedValue(); }
|
|
virtual HRESULT STDMETHODCALLTYPE SetEventOnCompletion(UINT64 Value, HANDLE hEvent)
|
|
{
|
|
return m_pReal->SetEventOnCompletion(Value, hEvent);
|
|
}
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE Signal(UINT64 Value) { return m_pReal->Signal(Value); }
|
|
//////////////////////////////
|
|
// implement ID3D12Fence1
|
|
virtual D3D12_FENCE_FLAGS STDMETHODCALLTYPE GetCreationFlags()
|
|
{
|
|
ID3D12Fence1 *real1 = NULL;
|
|
m_pReal->QueryInterface(__uuidof(ID3D12Fence1), (void **)&real1);
|
|
|
|
if(!real1)
|
|
return D3D12_FENCE_FLAG_NONE;
|
|
|
|
D3D12_FENCE_FLAGS ret = real1->GetCreationFlags();
|
|
|
|
SAFE_RELEASE(real1);
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
class WrappedID3D12ProtectedResourceSession
|
|
: public WrappedDeviceChild12<ID3D12ProtectedResourceSession, ID3D12ProtectedResourceSession1>
|
|
{
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12ProtectedResourceSession);
|
|
|
|
enum
|
|
{
|
|
TypeEnum = Resource_ProtectedResourceSession,
|
|
};
|
|
|
|
WrappedID3D12ProtectedResourceSession(ID3D12ProtectedResourceSession *real,
|
|
WrappedID3D12Device *device)
|
|
: WrappedDeviceChild12(real, device)
|
|
{
|
|
}
|
|
virtual ~WrappedID3D12ProtectedResourceSession() { Shutdown(); }
|
|
//////////////////////////////
|
|
// implement ID3D12ProtectedSession
|
|
virtual HRESULT STDMETHODCALLTYPE GetStatusFence(REFIID riid, _COM_Outptr_opt_ void **ppFence)
|
|
{
|
|
if(riid != __uuidof(ID3D12Fence) && riid != __uuidof(ID3D12Fence1))
|
|
{
|
|
RDCERR("Unsupported fence interface %s", ToStr(riid).c_str());
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
void *iface = NULL;
|
|
HRESULT ret = m_pReal->GetStatusFence(riid, &iface);
|
|
|
|
if(ret != S_OK)
|
|
return ret;
|
|
|
|
ID3D12Fence *fence = NULL;
|
|
|
|
if(riid == __uuidof(ID3D12Fence))
|
|
fence = (ID3D12Fence *)iface;
|
|
else if(riid == __uuidof(ID3D12Fence1))
|
|
fence = (ID3D12Fence *)(ID3D12Fence1 *)iface;
|
|
|
|
*ppFence = m_pDevice->CreateProtectedSessionFence(fence);
|
|
return S_OK;
|
|
}
|
|
|
|
virtual D3D12_PROTECTED_SESSION_STATUS STDMETHODCALLTYPE GetSessionStatus(void)
|
|
{
|
|
return m_pReal->GetSessionStatus();
|
|
}
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12ProtectedResourceSession
|
|
virtual D3D12_PROTECTED_RESOURCE_SESSION_DESC STDMETHODCALLTYPE GetDesc(void)
|
|
{
|
|
return m_pReal->GetDesc();
|
|
}
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12ProtectedResourceSession1
|
|
virtual D3D12_PROTECTED_RESOURCE_SESSION_DESC1 STDMETHODCALLTYPE GetDesc1()
|
|
{
|
|
ID3D12ProtectedResourceSession1 *real1 = NULL;
|
|
m_pReal->QueryInterface(__uuidof(ID3D12ProtectedResourceSession1), (void **)&real1);
|
|
|
|
if(!real1)
|
|
return {};
|
|
|
|
D3D12_PROTECTED_RESOURCE_SESSION_DESC1 ret = real1->GetDesc1();
|
|
|
|
SAFE_RELEASE(real1);
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
class WrappedID3D12Heap : public WrappedDeviceChild12<ID3D12Heap, ID3D12Heap1>
|
|
{
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12Heap);
|
|
|
|
enum
|
|
{
|
|
TypeEnum = Resource_Heap,
|
|
};
|
|
|
|
WrappedID3D12Heap(ID3D12Heap *real, WrappedID3D12Device *device)
|
|
: WrappedDeviceChild12(real, device)
|
|
{
|
|
}
|
|
virtual ~WrappedID3D12Heap() { Shutdown(); }
|
|
//////////////////////////////
|
|
// implement ID3D12Heap
|
|
virtual D3D12_HEAP_DESC STDMETHODCALLTYPE GetDesc() { return m_pReal->GetDesc(); }
|
|
//////////////////////////////
|
|
// implement ID3D12Heap1
|
|
virtual HRESULT STDMETHODCALLTYPE
|
|
GetProtectedResourceSession(REFIID riid, _COM_Outptr_opt_ void **ppProtectedSession)
|
|
{
|
|
ID3D12Heap1 *real1 = NULL;
|
|
m_pReal->QueryInterface(__uuidof(ID3D12Heap1), (void **)&real1);
|
|
|
|
if(!real1)
|
|
return E_NOINTERFACE;
|
|
|
|
void *iface = NULL;
|
|
HRESULT ret = real1->GetProtectedResourceSession(riid, &iface);
|
|
|
|
SAFE_RELEASE(real1);
|
|
|
|
if(ret != S_OK)
|
|
return ret;
|
|
|
|
if(riid == __uuidof(ID3D12ProtectedResourceSession))
|
|
{
|
|
*ppProtectedSession = new WrappedID3D12ProtectedResourceSession(
|
|
(ID3D12ProtectedResourceSession *)iface, m_pDevice);
|
|
}
|
|
else
|
|
{
|
|
RDCERR("Unsupported interface %s", ToStr(riid).c_str());
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
};
|
|
|
|
class WrappedID3D12PipelineState : public WrappedDeviceChild12<ID3D12PipelineState>
|
|
{
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12PipelineState);
|
|
|
|
D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC *graphics = NULL;
|
|
D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC *compute = NULL;
|
|
|
|
rdcarray<DescriptorAccess> staticDescriptorAccess;
|
|
bool m_AccessProcessed = false;
|
|
|
|
void Fill(D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC &desc)
|
|
{
|
|
if(graphics)
|
|
{
|
|
desc = *graphics;
|
|
if(VS())
|
|
desc.VS = VS()->GetDesc();
|
|
if(HS())
|
|
desc.HS = HS()->GetDesc();
|
|
if(DS())
|
|
desc.DS = DS()->GetDesc();
|
|
if(GS())
|
|
desc.GS = GS()->GetDesc();
|
|
if(PS())
|
|
desc.PS = PS()->GetDesc();
|
|
if(AS())
|
|
desc.AS = AS()->GetDesc();
|
|
if(MS())
|
|
desc.MS = MS()->GetDesc();
|
|
}
|
|
else
|
|
{
|
|
desc = *compute;
|
|
desc.CS = CS()->GetDesc();
|
|
}
|
|
}
|
|
|
|
bool IsGraphics() { return graphics != NULL; }
|
|
bool IsCompute() { return compute != NULL; }
|
|
struct DXBCKey
|
|
{
|
|
DXBCKey(const D3D12_SHADER_BYTECODE &byteCode)
|
|
{
|
|
byteLen = (uint32_t)byteCode.BytecodeLength;
|
|
DXBC::DXBCContainer::GetHash(hash, byteCode.pShaderBytecode, byteCode.BytecodeLength);
|
|
}
|
|
|
|
// assume that byte length + hash is enough to uniquely identify a shader bytecode
|
|
uint32_t byteLen;
|
|
uint32_t hash[4];
|
|
|
|
bool operator<(const DXBCKey &o) const
|
|
{
|
|
if(byteLen != o.byteLen)
|
|
return byteLen < o.byteLen;
|
|
|
|
for(size_t i = 0; i < 4; i++)
|
|
if(hash[i] != o.hash[i])
|
|
return hash[i] < o.hash[i];
|
|
|
|
return false;
|
|
}
|
|
|
|
bool operator==(const DXBCKey &o) const
|
|
{
|
|
return byteLen == o.byteLen && hash[0] == o.hash[0] && hash[1] == o.hash[1] &&
|
|
hash[2] == o.hash[2] && hash[3] == o.hash[3];
|
|
}
|
|
};
|
|
|
|
class ShaderEntry : public WrappedDeviceChild12<ID3D12DeviceChild>
|
|
{
|
|
public:
|
|
static bool m_InternalResources;
|
|
|
|
static void InternalResources(bool internalResources)
|
|
{
|
|
m_InternalResources = internalResources;
|
|
}
|
|
|
|
ShaderEntry(const D3D12_SHADER_BYTECODE &byteCode, WrappedID3D12Device *device)
|
|
: WrappedDeviceChild12(NULL, device), m_Key(byteCode)
|
|
{
|
|
m_Bytecode.assign((const byte *)byteCode.pShaderBytecode, byteCode.BytecodeLength);
|
|
m_DXBCFile = NULL;
|
|
m_Details = new ShaderReflection;
|
|
|
|
device->GetResourceManager()->AddLiveResource(GetResourceID(), this);
|
|
|
|
if(!m_InternalResources)
|
|
{
|
|
device->AddResource(GetResourceID(), ResourceType::Shader, "Shader");
|
|
|
|
ResourceDescription &desc = device->GetResourceDesc(GetResourceID());
|
|
// this will be appended to in the function above.
|
|
desc.initialisationChunks.clear();
|
|
|
|
// since these don't have live IDs, let's use the first uint of the hash as the name. Slight
|
|
// chance of collision but not that bad.
|
|
desc.name = StringFormat::Fmt("Shader {%08x}", m_Key.hash[0]);
|
|
}
|
|
|
|
m_Built = false;
|
|
}
|
|
|
|
virtual ~ShaderEntry()
|
|
{
|
|
m_Shaders.erase(m_Key);
|
|
m_Bytecode.clear();
|
|
SAFE_DELETE(m_DXBCFile);
|
|
SAFE_DELETE(m_Details);
|
|
Shutdown();
|
|
}
|
|
ShaderEntry(const ShaderEntry &e) = delete;
|
|
ShaderEntry &operator=(const ShaderEntry &e) = delete;
|
|
|
|
static ShaderEntry *AddShader(const D3D12_SHADER_BYTECODE &byteCode, WrappedID3D12Device *device)
|
|
{
|
|
DXBCKey key(byteCode);
|
|
ShaderEntry *shader = m_Shaders[key];
|
|
|
|
if(shader == NULL)
|
|
shader = m_Shaders[key] = new ShaderEntry(byteCode, device);
|
|
|
|
return shader;
|
|
}
|
|
|
|
static void ReleaseShader(ShaderEntry *shader)
|
|
{
|
|
if(shader == NULL)
|
|
return;
|
|
|
|
shader->Release();
|
|
}
|
|
|
|
static bool IsShader(ResourceId id)
|
|
{
|
|
for(auto it = m_Shaders.begin(); it != m_Shaders.end(); ++it)
|
|
if(it->second->GetResourceID() == id)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
static void GetReflections(rdcarray<ShaderReflection *> &refls)
|
|
{
|
|
refls.clear();
|
|
for(auto it = m_Shaders.begin(); it != m_Shaders.end(); ++it)
|
|
{
|
|
refls.push_back(it->second->m_Details);
|
|
it->second->m_Details = NULL;
|
|
}
|
|
}
|
|
|
|
void GetShaderExtSlot(uint32_t &slot, uint32_t &space)
|
|
{
|
|
slot = m_ShaderExtSlot;
|
|
space = m_ShaderExtSpace;
|
|
}
|
|
|
|
void SetShaderExtSlot(uint32_t slot, uint32_t space)
|
|
{
|
|
// it doesn't make sense to build the same DXBC with different slots/spaces since it's baked
|
|
// in.
|
|
|
|
if(slot != m_ShaderExtSlot && m_ShaderExtSlot != ~0U)
|
|
RDCERR(
|
|
"Unexpected case - different valid slot %u being set for same shader already "
|
|
"configured with slot %u",
|
|
slot, m_ShaderExtSlot);
|
|
if(space != m_ShaderExtSpace && m_ShaderExtSpace != ~0U)
|
|
RDCERR(
|
|
"Unexpected case - different valid space %u being set for same shader already "
|
|
"configured with space %u",
|
|
space, m_ShaderExtSpace);
|
|
|
|
m_ShaderExtSlot = slot;
|
|
m_ShaderExtSpace = space;
|
|
}
|
|
|
|
DXBCKey GetKey() { return m_Key; }
|
|
D3D12_SHADER_BYTECODE GetDesc()
|
|
{
|
|
D3D12_SHADER_BYTECODE ret;
|
|
ret.BytecodeLength = m_Bytecode.size();
|
|
ret.pShaderBytecode = (const void *)&m_Bytecode[0];
|
|
return ret;
|
|
}
|
|
|
|
DXBC::DXBCContainer *GetDXBC()
|
|
{
|
|
if(m_DXBCFile == NULL && !m_Bytecode.empty())
|
|
{
|
|
m_DXBCFile = new DXBC::DXBCContainer(m_Bytecode, rdcstr(), GraphicsAPI::D3D12,
|
|
m_ShaderExtSlot, m_ShaderExtSpace);
|
|
}
|
|
return m_DXBCFile;
|
|
}
|
|
ShaderReflection &GetDetails()
|
|
{
|
|
if(!m_Built && GetDXBC() != NULL)
|
|
BuildReflection();
|
|
m_Built = true;
|
|
return *m_Details;
|
|
}
|
|
|
|
private:
|
|
void TryReplaceOriginalByteCode();
|
|
|
|
void BuildReflection();
|
|
|
|
DXBCKey m_Key;
|
|
|
|
bytebuf m_Bytecode;
|
|
uint32_t m_ShaderExtSlot = ~0U, m_ShaderExtSpace = ~0U;
|
|
|
|
bool m_Built;
|
|
DXBC::DXBCContainer *m_DXBCFile;
|
|
ShaderReflection *m_Details;
|
|
|
|
static std::map<DXBCKey, ShaderEntry *> m_Shaders;
|
|
};
|
|
|
|
enum
|
|
{
|
|
TypeEnum = Resource_PipelineState,
|
|
};
|
|
|
|
ShaderEntry *VS() { return graphics ? (ShaderEntry *)graphics->VS.pShaderBytecode : NULL; }
|
|
ShaderEntry *HS() { return graphics ? (ShaderEntry *)graphics->HS.pShaderBytecode : NULL; }
|
|
ShaderEntry *DS() { return graphics ? (ShaderEntry *)graphics->DS.pShaderBytecode : NULL; }
|
|
ShaderEntry *GS() { return graphics ? (ShaderEntry *)graphics->GS.pShaderBytecode : NULL; }
|
|
ShaderEntry *PS() { return graphics ? (ShaderEntry *)graphics->PS.pShaderBytecode : NULL; }
|
|
ShaderEntry *AS() { return graphics ? (ShaderEntry *)graphics->AS.pShaderBytecode : NULL; }
|
|
ShaderEntry *MS() { return graphics ? (ShaderEntry *)graphics->MS.pShaderBytecode : NULL; }
|
|
ShaderEntry *CS() { return compute ? (ShaderEntry *)compute->CS.pShaderBytecode : NULL; }
|
|
WrappedID3D12PipelineState(ID3D12PipelineState *real, WrappedID3D12Device *device)
|
|
: WrappedDeviceChild12(real, device)
|
|
{
|
|
if(IsReplayMode(m_pDevice->GetState()))
|
|
m_pDevice->GetPipelineList().push_back(this);
|
|
}
|
|
virtual ~WrappedID3D12PipelineState()
|
|
{
|
|
if(IsReplayMode(m_pDevice->GetState()))
|
|
m_pDevice->GetPipelineList().removeOne(this);
|
|
|
|
Shutdown();
|
|
|
|
if(graphics)
|
|
{
|
|
ShaderEntry::ReleaseShader(VS());
|
|
ShaderEntry::ReleaseShader(HS());
|
|
ShaderEntry::ReleaseShader(DS());
|
|
ShaderEntry::ReleaseShader(GS());
|
|
ShaderEntry::ReleaseShader(PS());
|
|
ShaderEntry::ReleaseShader(AS());
|
|
ShaderEntry::ReleaseShader(MS());
|
|
|
|
SAFE_DELETE_ARRAY(graphics->InputLayout.pInputElementDescs);
|
|
SAFE_DELETE_ARRAY(graphics->StreamOutput.pSODeclaration);
|
|
SAFE_DELETE_ARRAY(graphics->StreamOutput.pBufferStrides);
|
|
SAFE_DELETE_ARRAY(graphics->ViewInstancing.pViewInstanceLocations);
|
|
|
|
SAFE_DELETE(graphics);
|
|
}
|
|
|
|
if(compute)
|
|
{
|
|
ShaderEntry::ReleaseShader(CS());
|
|
|
|
SAFE_DELETE(compute);
|
|
}
|
|
}
|
|
|
|
void ProcessDescriptorAccess();
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12PipelineState
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetCachedBlob(ID3DBlob **ppBlob)
|
|
{
|
|
return m_pReal->GetCachedBlob(ppBlob);
|
|
}
|
|
};
|
|
|
|
// the priorities of subobject associations. Default associations are not(?) inherited from
|
|
// collections into PSOs, and are not inherited from DXIL libraries into state objects.
|
|
// explicit associations are passed down from collection to state object but have the lowest priority of them all
|
|
enum class SubObjectPriority : uint16_t
|
|
{
|
|
NotYetDefined,
|
|
// an explicit association in a collection - either from DXIL or code matters not by the time we
|
|
// get to a PSO including the collection
|
|
CollectionExplicitAssociation,
|
|
// subobject declared in DXIL in the same library but not associated at all
|
|
DXILImplicitDefault,
|
|
// subobject declared in DXIL and defaulted but just with an empty export string'
|
|
DXILExplicitDefault,
|
|
// subobject declared in DXIL and explicitly associated to an export
|
|
DXILExplicitAssociation,
|
|
// Object declared in code but not associated at all
|
|
CodeImplicitDefault,
|
|
// Object declared in code and defaulted with NULL export array
|
|
CodeExplicitDefault,
|
|
// Object declared in code and explicitly associated to an export
|
|
CodeExplicitAssociation,
|
|
};
|
|
|
|
typedef WrappedID3D12PipelineState::ShaderEntry WrappedID3D12Shader;
|
|
|
|
struct D3D12ShaderExportDatabase : public RefCounter12<IUnknown>
|
|
{
|
|
public:
|
|
D3D12ShaderExportDatabase(ResourceId id, D3D12RaytracingResourceAndUtilHandler *rayManager,
|
|
ID3D12StateObjectProperties *obj);
|
|
~D3D12ShaderExportDatabase();
|
|
|
|
ResourceId GetResourceId() { return objectOriginalId; }
|
|
|
|
void PopulateDatabase(size_t NumSubobjects, const D3D12_STATE_SUBOBJECT *subobjects);
|
|
|
|
void *GetShaderIdentifier(const rdcstr &exportName)
|
|
{
|
|
RDCCOMPILE_ASSERT(sizeof(D3D12ShaderExportDatabase::ShaderIdentifier) ==
|
|
D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES,
|
|
"Shader Identifier is wrongly sized");
|
|
for(size_t i = 0; i < exportLookups.size(); i++)
|
|
if(exportLookups[i].name == exportName || exportLookups[i].altName == exportName)
|
|
return exportLookups[i].complete ? &wrappedIdentifiers[i] : NULL;
|
|
return NULL;
|
|
}
|
|
|
|
struct ExportedIdentifier
|
|
{
|
|
// the unwrapped identifier to patch the contents of ShaderIdentifier into
|
|
uint32_t real[8];
|
|
// the index of the local root signature data to look up if local parameters need to be patched.
|
|
uint16_t localRootSigIndex;
|
|
// Subobjects have many different levels of priority they can come from, and the correct maximum
|
|
// level may not be clear for a while and may be overridden late. This keeps track of where we
|
|
// got the root signature from so that it can be overridden as necessary
|
|
SubObjectPriority rootSigPrio;
|
|
};
|
|
|
|
// unwrapped identifiers of NON-INHERITED NEWLY CREATED exports
|
|
// inherited exports are stored in the ownExports array of the database created for those objects,
|
|
// even if the objects themselves are not even around anymore - since the identifiers returned for
|
|
// them need to stay valid.
|
|
rdcarray<ExportedIdentifier> ownExports;
|
|
|
|
private:
|
|
// the state object that originally created this export database. Some of our shader identifiers
|
|
// may come from other databases, but when uploading the unwrap buffer we store information such
|
|
// that if we want to unwrap an identifier that comes from this id we look up into unwrappedOwnExports
|
|
// below. This is the original ID since this is used to look up identifiers that came from the application
|
|
ResourceId objectOriginalId;
|
|
|
|
rdcarray<D3D12ShaderExportDatabase *> parents;
|
|
|
|
ID3D12StateObjectProperties *m_StateObjectProps = NULL;
|
|
D3D12RaytracingResourceAndUtilHandler *m_RayManager = NULL;
|
|
|
|
struct ExportLookup
|
|
{
|
|
ExportLookup(rdcstr name, rdcstr altName, bool complete)
|
|
: name(name), altName(altName), complete(complete)
|
|
{
|
|
}
|
|
ExportLookup() = default;
|
|
|
|
// name of an export
|
|
rdcstr name;
|
|
// alternate names - for when name is mangled and unmangled names can be looked up
|
|
rdcstr altName;
|
|
// is this export complete - we rely on the runtime to resolve all the arcane rules and do any
|
|
// DXIL linking to tell if this export is actually complete or not.
|
|
// the first object where a shader identifier comes back is the one where we store the wrapped
|
|
// identifier, since identifiers must be cross-compatible and persistent
|
|
bool complete = false;
|
|
// whether this export is a hitgroup - incomplete hitgroups get inherited explicitly
|
|
bool hitgroup = false;
|
|
};
|
|
|
|
struct ShaderIdentifier
|
|
{
|
|
ResourceId id; // the object which has the actual identifier in its ownExports array
|
|
uint32_t index; // the index in the object's ownExports array
|
|
uint32_t pad[5]; // padding up to D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES
|
|
};
|
|
|
|
// wrapped identifiers for all exports in this database, ready to return to the application,
|
|
// including any inherited from parent objects and not referring to our exports
|
|
rdcarray<ShaderIdentifier> wrappedIdentifiers;
|
|
|
|
// parallel array to wrappedIdentifiers of export lookup information. This is parallel and not
|
|
// in-line with wrappedIdentifiers because we want that to be a tight array of actual identifiers
|
|
rdcarray<ExportLookup> exportLookups;
|
|
|
|
// these are not technically part of the 'exports' interface but they are very helpful to keep
|
|
// around at the same time. These are explicit associations which might yet apply to future
|
|
// exports in child state objects
|
|
rdcarray<rdcpair<rdcstr, uint32_t>> danglingRootSigAssocs;
|
|
rdcarray<rdcpair<rdcstr, rdcstr>> danglingDXILRootSigAssocs;
|
|
rdcflatmap<rdcstr, uint32_t> danglingDXILLocalRootSigs;
|
|
|
|
// list of hitgroups, with the name of the hit group export and the names of each shader export
|
|
// we can't precalculate the indices in this list because they could be dangling references that
|
|
// get inherited, so we have to do string lookups every time
|
|
rdcarray<rdcpair<rdcstr, rdcarray<rdcstr>>> hitGroups;
|
|
|
|
void InheritExport(const rdcstr &exportName, D3D12ShaderExportDatabase *existing, size_t i);
|
|
|
|
void ApplyRoot(const ShaderIdentifier &identifier, SubObjectPriority priority,
|
|
uint32_t localRootSigIndex);
|
|
|
|
// register our own newly created export
|
|
void AddExport(const rdcstr &exportName);
|
|
|
|
// import some or all of a collection's exports
|
|
void InheritCollectionExport(D3D12ShaderExportDatabase *existing, const rdcstr &nameToExport,
|
|
const rdcstr &nameInExisting);
|
|
void InheritAllCollectionExports(D3D12ShaderExportDatabase *existing);
|
|
|
|
// we only apply root signature associations to our own exports. Anything that was considered exported
|
|
// in a parent object was already final and either had a local root signature, or didn't need one at all.
|
|
void ApplyDefaultRoot(SubObjectPriority priority, uint32_t localRootSigIndex);
|
|
void ApplyRoot(SubObjectPriority priority, const rdcstr &exportName, uint32_t localRootSigIndex);
|
|
|
|
// register a hit group for local root sig inheritance
|
|
void AddLastHitGroupShaders(rdcarray<rdcstr> &&shaders);
|
|
void UpdateHitGroupAssociations();
|
|
};
|
|
|
|
class WrappedID3D12StateObject : public WrappedDeviceChild12<ID3D12StateObject>,
|
|
public ID3D12StateObjectProperties
|
|
{
|
|
ID3D12StateObjectProperties *properties;
|
|
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12StateObject);
|
|
|
|
D3D12ShaderExportDatabase *exports = NULL;
|
|
|
|
enum
|
|
{
|
|
TypeEnum = Resource_StateObject,
|
|
};
|
|
|
|
WrappedID3D12StateObject(ID3D12StateObject *real, WrappedID3D12Device *device)
|
|
: WrappedDeviceChild12(real, device)
|
|
{
|
|
real->QueryInterface(__uuidof(ID3D12StateObjectProperties), (void **)&properties);
|
|
}
|
|
virtual ~WrappedID3D12StateObject()
|
|
{
|
|
SAFE_RELEASE(properties);
|
|
SAFE_RELEASE(exports);
|
|
Shutdown();
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE AddRef() { return WrappedDeviceChild12::AddRef(); }
|
|
ULONG STDMETHODCALLTYPE Release() { return WrappedDeviceChild12::Release(); }
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
|
|
{
|
|
if(riid == __uuidof(ID3D12StateObjectProperties))
|
|
{
|
|
*ppvObject = (ID3D12StateObjectProperties *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
return WrappedDeviceChild12::QueryInterface(riid, ppvObject);
|
|
}
|
|
|
|
ID3D12StateObjectProperties *GetProperties() const { return properties; }
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12StateObject
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12StateObjectProperties
|
|
|
|
virtual void *STDMETHODCALLTYPE GetShaderIdentifier(LPCWSTR pExportName)
|
|
{
|
|
return exports->GetShaderIdentifier(StringFormat::Wide2UTF8(pExportName));
|
|
}
|
|
virtual UINT64 STDMETHODCALLTYPE GetShaderStackSize(LPCWSTR pExportName)
|
|
{
|
|
return properties->GetShaderStackSize(pExportName);
|
|
}
|
|
virtual UINT64 STDMETHODCALLTYPE GetPipelineStackSize()
|
|
{
|
|
return properties->GetPipelineStackSize();
|
|
}
|
|
virtual void STDMETHODCALLTYPE SetPipelineStackSize(UINT64 PipelineStackSizeInBytes)
|
|
{
|
|
properties->SetPipelineStackSize(PipelineStackSizeInBytes);
|
|
}
|
|
};
|
|
|
|
class WrappedID3D12QueryHeap : public WrappedDeviceChild12<ID3D12QueryHeap>
|
|
{
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12QueryHeap);
|
|
|
|
enum
|
|
{
|
|
TypeEnum = Resource_QueryHeap,
|
|
};
|
|
|
|
WrappedID3D12QueryHeap(ID3D12QueryHeap *real, WrappedID3D12Device *device)
|
|
: WrappedDeviceChild12(real, device)
|
|
{
|
|
}
|
|
virtual ~WrappedID3D12QueryHeap() { Shutdown(); }
|
|
};
|
|
|
|
class D3D12AccelerationStructure;
|
|
|
|
class WrappedID3D12Resource
|
|
: public WrappedDeviceChild12<ID3D12Resource, ID3D12Resource1, ID3D12Resource2>
|
|
{
|
|
static GPUAddressRangeTracker m_Addresses;
|
|
static rdcarray<ResourceId> m_bufferResources;
|
|
|
|
WriteSerialiser &GetThreadSerialiser();
|
|
size_t DeleteOverlappingAccStructsInRangeAtOffset(D3D12BufferOffset bufferOffset);
|
|
|
|
WrappedID3D12Heap *m_Heap = NULL;
|
|
|
|
Threading::CriticalSection m_accStructResourcesCS;
|
|
rdcflatmap<D3D12BufferOffset, D3D12AccelerationStructure *> m_accelerationStructMap;
|
|
bool m_isAccelerationStructureResource = false;
|
|
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12Resource, false);
|
|
|
|
bool IsResident()
|
|
{
|
|
if(m_Heap)
|
|
return m_Heap->IsResident();
|
|
return WrappedDeviceChild12::IsResident();
|
|
}
|
|
|
|
WrappedID3D12Heap *GetHeap() { return m_Heap; }
|
|
|
|
ID3D12Pageable *UnwrappedResidencyPageable()
|
|
{
|
|
if(m_Heap)
|
|
return m_Heap->GetReal();
|
|
return this->GetReal();
|
|
}
|
|
|
|
ResourceId GetMappableID()
|
|
{
|
|
if(m_Heap)
|
|
return m_Heap->GetResourceID();
|
|
return this->GetResourceID();
|
|
}
|
|
|
|
bool CreateAccStruct(D3D12BufferOffset bufferOffset, UINT64 byteSize,
|
|
D3D12AccelerationStructure **accStruct);
|
|
|
|
bool GetAccStructIfExist(D3D12BufferOffset bufferOffset,
|
|
D3D12AccelerationStructure **accStruct = NULL);
|
|
|
|
bool DeleteAccStructAtOffset(D3D12BufferOffset bufferOffset);
|
|
|
|
bool IsAccelerationStructureResource() const { return m_isAccelerationStructureResource; }
|
|
void MarkAsAccelerationStructureResource() { m_isAccelerationStructureResource = true; }
|
|
static void MarkAllBufferResourceFrameReferenced(D3D12ResourceManager *rm)
|
|
{
|
|
for(ResourceId id : m_bufferResources)
|
|
{
|
|
rm->MarkResourceFrameReferenced(id, eFrameRef_Read);
|
|
}
|
|
}
|
|
|
|
static void RefBuffers(D3D12ResourceManager *rm);
|
|
static void GetMappableIDs(D3D12ResourceManager *rm, const std::unordered_set<ResourceId> &refdIDs,
|
|
std::unordered_set<ResourceId> &mappableIDs);
|
|
|
|
static rdcarray<ID3D12Resource *> AddRefBuffersBeforeCapture(D3D12ResourceManager *rm);
|
|
|
|
static void GetResIDFromAddr(D3D12_GPU_VIRTUAL_ADDRESS addr, ResourceId &id, UINT64 &offs)
|
|
{
|
|
m_Addresses.GetResIDFromAddr(addr, id, offs);
|
|
}
|
|
|
|
static void GetResIDFromAddrAllowOutOfBounds(D3D12_GPU_VIRTUAL_ADDRESS addr, ResourceId &id,
|
|
UINT64 &offs)
|
|
{
|
|
m_Addresses.GetResIDFromAddrAllowOutOfBounds(addr, id, offs);
|
|
}
|
|
|
|
// overload to just return the id in case the offset isn't needed
|
|
static ResourceId GetResIDFromAddr(D3D12_GPU_VIRTUAL_ADDRESS addr)
|
|
{
|
|
ResourceId id;
|
|
UINT64 offs;
|
|
|
|
m_Addresses.GetResIDFromAddr(addr, id, offs);
|
|
|
|
return id;
|
|
}
|
|
|
|
enum
|
|
{
|
|
TypeEnum = Resource_Resource,
|
|
};
|
|
|
|
WrappedID3D12Resource(ID3D12Resource *real, ID3D12Heap *heap, UINT64 HeapOffset,
|
|
WrappedID3D12Device *device)
|
|
: WrappedDeviceChild12(real, device)
|
|
{
|
|
if(IsReplayMode(device->GetState()))
|
|
device->AddReplayResource(GetResourceID(), this);
|
|
|
|
m_Heap = (WrappedID3D12Heap *)heap;
|
|
SAFE_ADDREF(m_Heap);
|
|
|
|
// assuming only valid for buffers
|
|
if(m_pReal->GetDesc().Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
|
|
{
|
|
D3D12_GPU_VIRTUAL_ADDRESS addr = m_pReal->GetGPUVirtualAddress();
|
|
|
|
GPUAddressRange range;
|
|
range.start = addr;
|
|
range.realEnd = addr + m_pReal->GetDesc().Width;
|
|
|
|
// if this is placed, the OOB end is all the way to the end of the heap, from where we're
|
|
// placed, allowing accesses past the buffer but still in bounds of the heap.
|
|
if(heap)
|
|
{
|
|
const UINT64 heapSize = heap->GetDesc().SizeInBytes;
|
|
range.oobEnd = addr + (heapSize - HeapOffset);
|
|
}
|
|
else
|
|
{
|
|
range.oobEnd = range.realEnd;
|
|
}
|
|
|
|
range.id = GetResourceID();
|
|
|
|
m_Addresses.AddTo(range);
|
|
|
|
m_bufferResources.push_back(GetResourceID());
|
|
}
|
|
}
|
|
virtual ~WrappedID3D12Resource();
|
|
|
|
byte *GetMap(UINT Subresource);
|
|
byte *GetShadow(UINT Subresource);
|
|
void AllocShadow(UINT Subresource, size_t size);
|
|
void FreeShadow();
|
|
void LockMaps();
|
|
void UnlockMaps();
|
|
|
|
virtual uint64_t GetGPUVirtualAddressIfBuffer()
|
|
{
|
|
if(m_pReal->GetDesc().Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
|
|
return m_pReal->GetGPUVirtualAddress();
|
|
return 0;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
|
|
{
|
|
if(riid == __uuidof(ID3D12ManualWriteTrackingResource))
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
return WrappedDeviceChild12::QueryInterface(riid, ppvObject);
|
|
}
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12Resource
|
|
|
|
virtual D3D12_RESOURCE_DESC STDMETHODCALLTYPE GetDesc() { return m_pReal->GetDesc(); }
|
|
virtual D3D12_GPU_VIRTUAL_ADDRESS STDMETHODCALLTYPE GetGPUVirtualAddress()
|
|
{
|
|
return m_pReal->GetGPUVirtualAddress();
|
|
}
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetHeapProperties(D3D12_HEAP_PROPERTIES *pHeapProperties,
|
|
D3D12_HEAP_FLAGS *pHeapFlags)
|
|
{
|
|
return m_pReal->GetHeapProperties(pHeapProperties, pHeapFlags);
|
|
}
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE Map(UINT Subresource, const D3D12_RANGE *pReadRange,
|
|
void **ppData);
|
|
virtual void STDMETHODCALLTYPE Unmap(UINT Subresource, const D3D12_RANGE *pWrittenRange);
|
|
virtual HRESULT STDMETHODCALLTYPE WriteToSubresource(UINT DstSubresource, const D3D12_BOX *pDstBox,
|
|
const void *pSrcData, UINT SrcRowPitch,
|
|
UINT SrcDepthPitch);
|
|
virtual HRESULT STDMETHODCALLTYPE ReadFromSubresource(void *pDstData, UINT DstRowPitch,
|
|
UINT DstDepthPitch, UINT SrcSubresource,
|
|
const D3D12_BOX *pSrcBox)
|
|
{
|
|
// don't have to do anything here
|
|
return m_pReal->ReadFromSubresource(pDstData, DstRowPitch, DstDepthPitch, SrcSubresource,
|
|
pSrcBox);
|
|
}
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12Resource1
|
|
virtual HRESULT STDMETHODCALLTYPE
|
|
GetProtectedResourceSession(REFIID riid, _COM_Outptr_opt_ void **ppProtectedSession)
|
|
{
|
|
ID3D12Resource1 *real1 = NULL;
|
|
m_pReal->QueryInterface(__uuidof(ID3D12Resource1), (void **)&real1);
|
|
|
|
if(!real1)
|
|
return E_NOINTERFACE;
|
|
|
|
void *iface = NULL;
|
|
HRESULT ret = real1->GetProtectedResourceSession(riid, &iface);
|
|
|
|
SAFE_RELEASE(real1);
|
|
|
|
if(ret != S_OK)
|
|
return ret;
|
|
|
|
if(riid == __uuidof(ID3D12ProtectedResourceSession))
|
|
{
|
|
*ppProtectedSession = new WrappedID3D12ProtectedResourceSession(
|
|
(ID3D12ProtectedResourceSession *)iface, m_pDevice);
|
|
}
|
|
else
|
|
{
|
|
RDCERR("Unsupported interface %s", ToStr(riid).c_str());
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12Resource2
|
|
virtual D3D12_RESOURCE_DESC1 STDMETHODCALLTYPE GetDesc1(void)
|
|
{
|
|
ID3D12Resource2 *real2 = NULL;
|
|
m_pReal->QueryInterface(__uuidof(ID3D12Resource2), (void **)&real2);
|
|
|
|
if(!real2)
|
|
return {};
|
|
|
|
D3D12_RESOURCE_DESC1 ret = real2->GetDesc1();
|
|
|
|
SAFE_RELEASE(real2);
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
class WrappedID3D12RootSignature : public WrappedDeviceChild12<ID3D12RootSignature>
|
|
{
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12RootSignature);
|
|
|
|
D3D12RootSignature sig;
|
|
uint32_t localRootSigIdx = ~0U;
|
|
|
|
enum
|
|
{
|
|
TypeEnum = Resource_RootSignature,
|
|
};
|
|
|
|
WrappedID3D12RootSignature(ID3D12RootSignature *real, WrappedID3D12Device *device)
|
|
: WrappedDeviceChild12(real, device)
|
|
{
|
|
}
|
|
virtual ~WrappedID3D12RootSignature() { Shutdown(); }
|
|
};
|
|
|
|
class WrappedID3D12PipelineLibrary : public WrappedDeviceChild12<ID3D12PipelineLibrary1>
|
|
{
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12PipelineLibrary);
|
|
|
|
enum
|
|
{
|
|
TypeEnum = Resource_PipelineLibrary,
|
|
};
|
|
|
|
WrappedID3D12PipelineLibrary(WrappedID3D12Device *device) : WrappedDeviceChild12(NULL, device) {}
|
|
virtual ~WrappedID3D12PipelineLibrary() { Shutdown(); }
|
|
virtual HRESULT STDMETHODCALLTYPE StorePipeline(_In_opt_ LPCWSTR pName,
|
|
_In_ ID3D12PipelineState *pPipeline)
|
|
{
|
|
// do nothing
|
|
return S_OK;
|
|
}
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE
|
|
LoadGraphicsPipeline(_In_ LPCWSTR pName, _In_ const D3D12_GRAPHICS_PIPELINE_STATE_DESC *pDesc,
|
|
REFIID riid, _COM_Outptr_ void **ppPipelineState)
|
|
{
|
|
// pretend we don't have it - assume that the application won't store then
|
|
// load in the same run, or will handle that if it happens
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE
|
|
LoadComputePipeline(_In_ LPCWSTR pName, _In_ const D3D12_COMPUTE_PIPELINE_STATE_DESC *pDesc,
|
|
REFIID riid, _COM_Outptr_ void **ppPipelineState)
|
|
{
|
|
// pretend we don't have it - assume that the application won't store then
|
|
// load in the same run, or will handle that if it happens
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
static const SIZE_T DummyBytes = 32;
|
|
|
|
virtual SIZE_T STDMETHODCALLTYPE GetSerializedSize(void)
|
|
{
|
|
// simple dummy serialisation since applications might not expect 0 bytes
|
|
return DummyBytes;
|
|
}
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE Serialize(_Out_writes_(DataSizeInBytes) void *pData,
|
|
SIZE_T DataSizeInBytes)
|
|
{
|
|
if(DataSizeInBytes < DummyBytes)
|
|
return E_INVALIDARG;
|
|
|
|
memset(pData, 0, DummyBytes);
|
|
return S_OK;
|
|
}
|
|
|
|
//////////////////////////////
|
|
// implement ID3D12PipelineLibrary1
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE LoadPipeline(LPCWSTR pName,
|
|
const D3D12_PIPELINE_STATE_STREAM_DESC *pDesc,
|
|
REFIID riid, void **ppPipelineState)
|
|
{
|
|
// pretend we don't have it - assume that the application won't store then
|
|
// load in the same run, or will handle that if it happens
|
|
return E_INVALIDARG;
|
|
}
|
|
};
|
|
|
|
class WrappedID3D12ShaderCacheSession : public WrappedDeviceChild12<ID3D12ShaderCacheSession>
|
|
{
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12ShaderCacheSession);
|
|
|
|
enum
|
|
{
|
|
TypeEnum = Resource_ShaderCacheSession,
|
|
};
|
|
|
|
WrappedID3D12ShaderCacheSession(ID3D12ShaderCacheSession *real, WrappedID3D12Device *device)
|
|
: WrappedDeviceChild12(real, device)
|
|
{
|
|
}
|
|
virtual ~WrappedID3D12ShaderCacheSession() { Shutdown(); }
|
|
//////////////////////////////
|
|
// implement ID3D12ShaderCacheSession
|
|
virtual HRESULT STDMETHODCALLTYPE FindValue(
|
|
/* [annotation][in] */
|
|
_In_reads_bytes_(KeySize) const void *pKey, UINT KeySize,
|
|
/* [annotation][out] */
|
|
_Out_writes_bytes_(*pValueSize) void *pValue, _Inout_ UINT *pValueSize)
|
|
{
|
|
return m_pReal->FindValue(pKey, KeySize, pValue, pValueSize);
|
|
}
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE StoreValue(
|
|
/* [annotation][in] */
|
|
_In_reads_bytes_(KeySize) const void *pKey, UINT KeySize,
|
|
/* [annotation][in] */
|
|
_In_reads_bytes_(ValueSize) const void *pValue, UINT ValueSize)
|
|
{
|
|
return m_pReal->StoreValue(pKey, KeySize, pValue, ValueSize);
|
|
}
|
|
|
|
virtual void STDMETHODCALLTYPE SetDeleteOnDestroy(void) { m_pReal->SetDeleteOnDestroy(); }
|
|
virtual D3D12_SHADER_CACHE_SESSION_DESC STDMETHODCALLTYPE GetDesc(void)
|
|
{
|
|
return m_pReal->GetDesc();
|
|
}
|
|
};
|
|
|
|
// class to represent acceleration structure i.e. BLAS/TLAS
|
|
class D3D12AccelerationStructure : public WrappedDeviceChild12<ID3D12DeviceChild>
|
|
{
|
|
public:
|
|
ALLOCATE_WITH_WRAPPED_POOL(D3D12AccelerationStructure);
|
|
|
|
D3D12AccelerationStructure(WrappedID3D12Device *wrappedDevice, WrappedID3D12Resource *bufferRes,
|
|
D3D12BufferOffset bufferOffset, UINT64 byteSize);
|
|
|
|
~D3D12AccelerationStructure();
|
|
|
|
uint64_t Size() const { return byteSize; }
|
|
ResourceId GetBackingBufferResourceId() const { return m_asbWrappedResource->GetResourceID(); }
|
|
D3D12_GPU_VIRTUAL_ADDRESS GetVirtualAddress() const
|
|
{
|
|
return m_asbWrappedResource->GetGPUVirtualAddress() + m_asbWrappedResourceBufferOffset;
|
|
}
|
|
|
|
private:
|
|
WrappedID3D12Resource *m_asbWrappedResource;
|
|
D3D12BufferOffset m_asbWrappedResourceBufferOffset;
|
|
UINT64 byteSize;
|
|
};
|
|
|
|
#define ALL_D3D12_TYPES \
|
|
D3D12_TYPE_MACRO(ID3D12CommandAllocator); \
|
|
D3D12_TYPE_MACRO(ID3D12CommandSignature); \
|
|
D3D12_TYPE_MACRO(ID3D12DescriptorHeap); \
|
|
D3D12_TYPE_MACRO(ID3D12Fence); \
|
|
D3D12_TYPE_MACRO(ID3D12Heap); \
|
|
D3D12_TYPE_MACRO(ID3D12PipelineState); \
|
|
D3D12_TYPE_MACRO(ID3D12QueryHeap); \
|
|
D3D12_TYPE_MACRO(ID3D12Resource); \
|
|
D3D12_TYPE_MACRO(ID3D12RootSignature); \
|
|
D3D12_TYPE_MACRO(ID3D12PipelineLibrary); \
|
|
D3D12_TYPE_MACRO(ID3D12ProtectedResourceSession); \
|
|
D3D12_TYPE_MACRO(ID3D12ShaderCacheSession); \
|
|
D3D12_TYPE_MACRO(ID3D12StateObject);
|
|
|
|
// template magic voodoo to unwrap types
|
|
template <typename inner>
|
|
struct UnwrapHelper
|
|
{
|
|
};
|
|
|
|
#undef D3D12_TYPE_MACRO
|
|
#define D3D12_TYPE_MACRO(iface) \
|
|
template <> \
|
|
struct UnwrapHelper<iface> \
|
|
{ \
|
|
typedef CONCAT(Wrapped, iface) Outer; \
|
|
static bool IsAlloc(void *ptr) \
|
|
{ \
|
|
return Outer::IsAlloc(ptr); \
|
|
} \
|
|
static D3D12ResourceType GetTypeEnum() \
|
|
{ \
|
|
return (D3D12ResourceType)Outer::TypeEnum; \
|
|
} \
|
|
static Outer *FromHandle(iface *wrapped) \
|
|
{ \
|
|
return (Outer *)wrapped; \
|
|
} \
|
|
}; \
|
|
template <> \
|
|
struct UnwrapHelper<CONCAT(Wrapped, iface)> \
|
|
{ \
|
|
typedef CONCAT(Wrapped, iface) Outer; \
|
|
static bool IsAlloc(void *ptr) \
|
|
{ \
|
|
return Outer::IsAlloc(ptr); \
|
|
} \
|
|
static D3D12ResourceType GetTypeEnum() \
|
|
{ \
|
|
return (D3D12ResourceType)Outer::TypeEnum; \
|
|
} \
|
|
static Outer *FromHandle(iface *wrapped) \
|
|
{ \
|
|
return (Outer *)wrapped; \
|
|
} \
|
|
};
|
|
|
|
ALL_D3D12_TYPES;
|
|
|
|
// extra helpers here for '1' or '2' extended interfaces
|
|
#define D3D12_UNWRAP_EXTENDED(iface, ifaceX) \
|
|
template <> \
|
|
struct UnwrapHelper<ifaceX> \
|
|
{ \
|
|
typedef CONCAT(Wrapped, iface) Outer; \
|
|
static bool IsAlloc(void *ptr) \
|
|
{ \
|
|
return Outer::IsAlloc(ptr); \
|
|
} \
|
|
static D3D12ResourceType GetTypeEnum() \
|
|
{ \
|
|
return (D3D12ResourceType)Outer::TypeEnum; \
|
|
} \
|
|
static Outer *FromHandle(ifaceX *wrapped) \
|
|
{ \
|
|
return (Outer *)wrapped; \
|
|
} \
|
|
};
|
|
|
|
D3D12_UNWRAP_EXTENDED(ID3D12Fence, ID3D12Fence1);
|
|
D3D12_UNWRAP_EXTENDED(ID3D12PipelineLibrary, ID3D12PipelineLibrary1);
|
|
D3D12_UNWRAP_EXTENDED(ID3D12Heap, ID3D12Heap1);
|
|
D3D12_UNWRAP_EXTENDED(ID3D12Resource, ID3D12Resource1);
|
|
D3D12_UNWRAP_EXTENDED(ID3D12Resource, ID3D12Resource2);
|
|
D3D12_UNWRAP_EXTENDED(ID3D12ProtectedResourceSession, ID3D12ProtectedResourceSession1);
|
|
|
|
D3D12ResourceType IdentifyTypeByPtr(ID3D12Object *ptr);
|
|
|
|
#define WRAPPING_DEBUG 0
|
|
|
|
template <typename iface>
|
|
typename UnwrapHelper<iface>::Outer *GetWrapped(iface *obj)
|
|
{
|
|
if(obj == NULL)
|
|
return NULL;
|
|
|
|
typename UnwrapHelper<iface>::Outer *wrapped = UnwrapHelper<iface>::FromHandle(obj);
|
|
|
|
#if WRAPPING_DEBUG
|
|
if(obj != NULL && !wrapped->IsAlloc(wrapped))
|
|
{
|
|
RDCERR("Trying to unwrap invalid type");
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
return wrapped;
|
|
}
|
|
|
|
class WrappedID3D12GraphicsCommandList;
|
|
|
|
template <typename ifaceptr>
|
|
ifaceptr Unwrap(ifaceptr obj)
|
|
{
|
|
if(obj == NULL)
|
|
return NULL;
|
|
|
|
return GetWrapped(obj)->GetReal();
|
|
}
|
|
|
|
template <typename ifaceptr>
|
|
ResourceId GetResID(ifaceptr obj)
|
|
{
|
|
if(obj == NULL)
|
|
return ResourceId();
|
|
|
|
return GetWrapped(obj)->GetResourceID();
|
|
}
|
|
|
|
template <typename ifaceptr>
|
|
D3D12ResourceRecord *GetRecord(ifaceptr obj)
|
|
{
|
|
if(obj == NULL)
|
|
return NULL;
|
|
|
|
return GetWrapped(obj)->GetResourceRecord();
|
|
}
|
|
|
|
// specialisations that use the IsAlloc() function to identify the real type
|
|
template <>
|
|
ResourceId GetResID(ID3D12Object *ptr);
|
|
template <>
|
|
ID3D12Object *Unwrap(ID3D12Object *ptr);
|
|
template <>
|
|
D3D12ResourceRecord *GetRecord(ID3D12Object *ptr);
|
|
|
|
template <>
|
|
ResourceId GetResID(ID3D12DeviceChild *ptr);
|
|
template <>
|
|
ResourceId GetResID(ID3D12Pageable *ptr);
|
|
template <>
|
|
ResourceId GetResID(ID3D12CommandList *ptr);
|
|
template <>
|
|
ResourceId GetResID(ID3D12GraphicsCommandList *ptr);
|
|
template <>
|
|
ResourceId GetResID(ID3D12CommandQueue *ptr);
|
|
template <>
|
|
ID3D12DeviceChild *Unwrap(ID3D12DeviceChild *ptr);
|
|
|
|
template <>
|
|
D3D12ResourceRecord *GetRecord(ID3D12DeviceChild *ptr);
|