mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 15:11:31 +00:00
[idd] d3d: add leased D3D11 texture interop
This commit is contained in:
@@ -51,6 +51,7 @@
|
|||||||
<ClCompile Include="capture\CHardwareFrameProcessor.cpp" />
|
<ClCompile Include="capture\CHardwareFrameProcessor.cpp" />
|
||||||
<ClCompile Include="capture\CSoftwareFrameProcessor.cpp" />
|
<ClCompile Include="capture\CSoftwareFrameProcessor.cpp" />
|
||||||
<ClCompile Include="capture\CSwapChainProcessor.cpp" />
|
<ClCompile Include="capture\CSwapChainProcessor.cpp" />
|
||||||
|
<ClCompile Include="d3d\CInteropPool.cpp" />
|
||||||
<ClCompile Include="d3d\CD3D11Device.cpp" />
|
<ClCompile Include="d3d\CD3D11Device.cpp" />
|
||||||
<ClCompile Include="d3d\CD3D12CommandQueue.cpp" />
|
<ClCompile Include="d3d\CD3D12CommandQueue.cpp" />
|
||||||
<ClCompile Include="d3d\CD3D12Device.cpp" />
|
<ClCompile Include="d3d\CD3D12Device.cpp" />
|
||||||
@@ -106,6 +107,7 @@
|
|||||||
<ClInclude Include="capture\CHardwareFrameProcessor.h" />
|
<ClInclude Include="capture\CHardwareFrameProcessor.h" />
|
||||||
<ClInclude Include="capture\CSoftwareFrameProcessor.h" />
|
<ClInclude Include="capture\CSoftwareFrameProcessor.h" />
|
||||||
<ClInclude Include="capture\CSwapChainProcessor.h" />
|
<ClInclude Include="capture\CSwapChainProcessor.h" />
|
||||||
|
<ClInclude Include="d3d\CInteropPool.h" />
|
||||||
<ClInclude Include="d3d\CD3D11Device.h" />
|
<ClInclude Include="d3d\CD3D11Device.h" />
|
||||||
<ClInclude Include="d3d\CD3D12CommandQueue.h" />
|
<ClInclude Include="d3d\CD3D12CommandQueue.h" />
|
||||||
<ClInclude Include="d3d\CD3D12Device.h" />
|
<ClInclude Include="d3d\CD3D12Device.h" />
|
||||||
|
|||||||
@@ -124,6 +124,9 @@
|
|||||||
<ClInclude Include="capture\CSwapChainProcessor.h">
|
<ClInclude Include="capture\CSwapChainProcessor.h">
|
||||||
<Filter>Capture</Filter>
|
<Filter>Capture</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="d3d\CInteropPool.h">
|
||||||
|
<Filter>D3D</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="d3d\CD3D11Device.h">
|
<ClInclude Include="d3d\CD3D11Device.h">
|
||||||
<Filter>D3D</Filter>
|
<Filter>D3D</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -303,6 +306,9 @@
|
|||||||
<ClCompile Include="capture\CSwapChainProcessor.cpp">
|
<ClCompile Include="capture\CSwapChainProcessor.cpp">
|
||||||
<Filter>Capture</Filter>
|
<Filter>Capture</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="d3d\CInteropPool.cpp">
|
||||||
|
<Filter>D3D</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="d3d\CD3D11Device.cpp">
|
<ClCompile Include="d3d\CD3D11Device.cpp">
|
||||||
<Filter>D3D</Filter>
|
<Filter>D3D</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
@@ -313,6 +313,17 @@ bool CFrameGraph::Want(FrameSignal signal) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CFrameGraph::Shared(unsigned node) const
|
||||||
|
{
|
||||||
|
if (!m_sealed || !node || node >= m_nodeCount)
|
||||||
|
return false;
|
||||||
|
for (unsigned i = 0; i < m_leafCount; ++i)
|
||||||
|
if (m_leaves[i].node == node &&
|
||||||
|
m_leaves[i].cfg.profile.storage == FrameStorage::D3D11_TEXTURE)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool CFrameGraph::Desc(unsigned leaf, const FrameContentRef& content,
|
bool CFrameGraph::Desc(unsigned leaf, const FrameContentRef& content,
|
||||||
LeafDesc& desc) const
|
LeafDesc& desc) const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ public:
|
|||||||
bool Same(const GraphCfg& cfg) const;
|
bool Same(const GraphCfg& cfg) const;
|
||||||
bool Want(FrameSignal signal) const;
|
bool Want(FrameSignal signal) const;
|
||||||
bool Need(FrameOp op) const;
|
bool Need(FrameOp op) const;
|
||||||
|
bool Shared(unsigned node) const;
|
||||||
bool Desc(unsigned leaf, const FrameContentRef& content,
|
bool Desc(unsigned leaf, const FrameContentRef& content,
|
||||||
LeafDesc& desc) const;
|
LeafDesc& desc) const;
|
||||||
|
|
||||||
|
|||||||
@@ -95,8 +95,9 @@ struct CTexCore
|
|||||||
unsigned node = 0;
|
unsigned node = 0;
|
||||||
unsigned count = 0;
|
unsigned count = 0;
|
||||||
FrameProfile profile;
|
FrameProfile profile;
|
||||||
D3D12_RESOURCE_DESC desc = {};
|
D3D12_RESOURCE_DESC desc = {};
|
||||||
D3D12_RESOURCE_STATES read = D3D12_RESOURCE_STATE_COMMON;
|
D3D12_RESOURCE_STATES read = D3D12_RESOURCE_STATE_COMMON;
|
||||||
|
bool shared = false;
|
||||||
Slot slots[CTexPool::MAX_SLOTS];
|
Slot slots[CTexPool::MAX_SLOTS];
|
||||||
|
|
||||||
TexResult Acquire(unsigned& index, uint64_t& generation)
|
TexResult Acquire(unsigned& index, uint64_t& generation)
|
||||||
@@ -279,10 +280,11 @@ CFrameTex::CFrameTex(uint64_t graphValue, uint64_t poolValue,
|
|||||||
unsigned nodeValue, unsigned slotValue, uint64_t versionValue,
|
unsigned nodeValue, unsigned slotValue, uint64_t versionValue,
|
||||||
const FrameProfile& profileValue,
|
const FrameProfile& profileValue,
|
||||||
const FrameDesc& frameValue, const ComPtr<ID3D12Resource>& res,
|
const FrameDesc& frameValue, const ComPtr<ID3D12Resource>& res,
|
||||||
const D12Sync& sync, D3D12_RESOURCE_STATES state) :
|
const D12Sync& sync, D3D12_RESOURCE_STATES state, bool sharedValue) :
|
||||||
m_res(res),
|
m_res(res),
|
||||||
m_sync(sync),
|
m_sync(sync),
|
||||||
m_state(state),
|
m_state(state),
|
||||||
|
m_shared(sharedValue),
|
||||||
graph(graphValue),
|
graph(graphValue),
|
||||||
pool(poolValue),
|
pool(poolValue),
|
||||||
node(nodeValue),
|
node(nodeValue),
|
||||||
@@ -389,7 +391,7 @@ bool TexWrite::Seal(const FrameDesc& frame, const D12Sync& sync,
|
|||||||
|
|
||||||
CFrameTex * raw = new (std::nothrow) CFrameTex(core->graph, core->id,
|
CFrameTex * raw = new (std::nothrow) CFrameTex(core->graph, core->id,
|
||||||
core->node, m_index, m_version, core->profile, desc, resource, sync,
|
core->node, m_index, m_version, core->profile, desc, resource, sync,
|
||||||
core->read);
|
core->read, core->shared);
|
||||||
if (!raw)
|
if (!raw)
|
||||||
{
|
{
|
||||||
core->Drop(index, generation);
|
core->Drop(index, generation);
|
||||||
@@ -429,7 +431,7 @@ void TexWrite::Cancel()
|
|||||||
TexResult CTexPool::Init(ID3D12Device3 * device, uint64_t graph,
|
TexResult CTexPool::Init(ID3D12Device3 * device, uint64_t graph,
|
||||||
unsigned node, const FrameProfile& profile,
|
unsigned node, const FrameProfile& profile,
|
||||||
const D3D12_RESOURCE_DESC& desc, D3D12_RESOURCE_STATES state,
|
const D3D12_RESOURCE_DESC& desc, D3D12_RESOURCE_STATES state,
|
||||||
unsigned slots)
|
unsigned slots, bool shared)
|
||||||
{
|
{
|
||||||
if (!device || !graph || !node || !slots || slots > MAX_SLOTS ||
|
if (!device || !graph || !node || !slots || slots > MAX_SLOTS ||
|
||||||
profile.storage != FrameStorage::D3D12_TEXTURE ||
|
profile.storage != FrameStorage::D3D12_TEXTURE ||
|
||||||
@@ -468,6 +470,7 @@ TexResult CTexPool::Init(ID3D12Device3 * device, uint64_t graph,
|
|||||||
core->profile = profile;
|
core->profile = profile;
|
||||||
core->desc = desc;
|
core->desc = desc;
|
||||||
core->read = state;
|
core->read = state;
|
||||||
|
core->shared = shared;
|
||||||
|
|
||||||
D3D12_HEAP_PROPERTIES heap = {};
|
D3D12_HEAP_PROPERTIES heap = {};
|
||||||
heap.Type = D3D12_HEAP_TYPE_DEFAULT;
|
heap.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||||
@@ -478,8 +481,12 @@ TexResult CTexPool::Init(ID3D12Device3 * device, uint64_t graph,
|
|||||||
|
|
||||||
for (unsigned i = 0; i < slots; ++i)
|
for (unsigned i = 0; i < slots; ++i)
|
||||||
{
|
{
|
||||||
|
const D3D12_HEAP_FLAGS flags = shared ?
|
||||||
|
static_cast<D3D12_HEAP_FLAGS>(D3D12_HEAP_FLAG_SHARED |
|
||||||
|
D3D12_HEAP_FLAG_CREATE_NOT_ZEROED) :
|
||||||
|
D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
|
||||||
const HRESULT hr = device->CreateCommittedResource(&heap,
|
const HRESULT hr = device->CreateCommittedResource(&heap,
|
||||||
D3D12_HEAP_FLAG_CREATE_NOT_ZEROED, &desc, state, nullptr,
|
flags, &desc, state, nullptr,
|
||||||
IID_PPV_ARGS(&core->slots[i].res));
|
IID_PPV_ARGS(&core->slots[i].res));
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,11 +47,12 @@ private:
|
|||||||
ComPtr<ID3D12Resource> m_res;
|
ComPtr<ID3D12Resource> m_res;
|
||||||
D12Sync m_sync;
|
D12Sync m_sync;
|
||||||
D3D12_RESOURCE_STATES m_state;
|
D3D12_RESOURCE_STATES m_state;
|
||||||
|
bool m_shared;
|
||||||
|
|
||||||
CFrameTex(uint64_t graph, uint64_t pool, unsigned node, unsigned slot,
|
CFrameTex(uint64_t graph, uint64_t pool, unsigned node, unsigned slot,
|
||||||
uint64_t version, const FrameProfile& profile, const FrameDesc& frame,
|
uint64_t version, const FrameProfile& profile, const FrameDesc& frame,
|
||||||
const ComPtr<ID3D12Resource>& res, const D12Sync& sync,
|
const ComPtr<ID3D12Resource>& res, const D12Sync& sync,
|
||||||
D3D12_RESOURCE_STATES state);
|
D3D12_RESOURCE_STATES state, bool shared);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CFrameTex(const CFrameTex&) = delete;
|
CFrameTex(const CFrameTex&) = delete;
|
||||||
@@ -68,6 +69,7 @@ public:
|
|||||||
ID3D12Resource * Get() const { return m_res.Get(); }
|
ID3D12Resource * Get() const { return m_res.Get(); }
|
||||||
const D12Sync& Sync() const { return m_sync; }
|
const D12Sync& Sync() const { return m_sync; }
|
||||||
D3D12_RESOURCE_STATES State() const { return m_state; }
|
D3D12_RESOURCE_STATES State() const { return m_state; }
|
||||||
|
bool Shared() const { return m_shared; }
|
||||||
bool Wait(CD3D12CommandSlot& cmd) const;
|
bool Wait(CD3D12CommandSlot& cmd) const;
|
||||||
D12SyncState Status() const { return m_sync.State(); }
|
D12SyncState Status() const { return m_sync.State(); }
|
||||||
bool Ready() const { return m_sync.Done(); }
|
bool Ready() const { return m_sync.Done(); }
|
||||||
@@ -152,7 +154,7 @@ public:
|
|||||||
|
|
||||||
TexResult Init(ID3D12Device3 * device, uint64_t graph, unsigned node,
|
TexResult Init(ID3D12Device3 * device, uint64_t graph, unsigned node,
|
||||||
const FrameProfile& profile, const D3D12_RESOURCE_DESC& desc,
|
const FrameProfile& profile, const D3D12_RESOURCE_DESC& desc,
|
||||||
D3D12_RESOURCE_STATES state, unsigned slots);
|
D3D12_RESOURCE_STATES state, unsigned slots, bool shared = false);
|
||||||
void Reset();
|
void Reset();
|
||||||
TexResult Try(TexWrite& write);
|
TexResult Try(TexWrite& write);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,11 +47,13 @@ HRESULT CD3D11Device::Init()
|
|||||||
|
|
||||||
ComPtr<ID3D11Device> device;
|
ComPtr<ID3D11Device> device;
|
||||||
ComPtr<ID3D11DeviceContext> context;
|
ComPtr<ID3D11DeviceContext> context;
|
||||||
|
const UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT |
|
||||||
|
(m_video ? D3D11_CREATE_DEVICE_VIDEO_SUPPORT : 0);
|
||||||
hr = D3D11CreateDevice(
|
hr = D3D11CreateDevice(
|
||||||
m_adapter.Get(),
|
m_adapter.Get(),
|
||||||
D3D_DRIVER_TYPE_UNKNOWN,
|
D3D_DRIVER_TYPE_UNKNOWN,
|
||||||
nullptr,
|
nullptr,
|
||||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
flags,
|
||||||
featureLevels,
|
featureLevels,
|
||||||
ARRAYSIZE(featureLevels),
|
ARRAYSIZE(featureLevels),
|
||||||
D3D11_SDK_VERSION,
|
D3D11_SDK_VERSION,
|
||||||
|
|||||||
@@ -36,11 +36,14 @@ private:
|
|||||||
ComPtr<IDXGIAdapter1 > m_adapter;
|
ComPtr<IDXGIAdapter1 > m_adapter;
|
||||||
ComPtr<ID3D11Device5 > m_device;
|
ComPtr<ID3D11Device5 > m_device;
|
||||||
ComPtr<ID3D11DeviceContext4> m_context;
|
ComPtr<ID3D11DeviceContext4> m_context;
|
||||||
bool m_isSoftware = false;
|
bool m_isSoftware = false;
|
||||||
|
bool m_video = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CD3D11Device(LUID adapterLuid) :
|
CD3D11Device(LUID adapterLuid, bool video = false) :
|
||||||
m_adapterLuid(adapterLuid) {};
|
m_adapterLuid(adapterLuid),
|
||||||
|
m_video(video)
|
||||||
|
{}
|
||||||
|
|
||||||
CD3D11Device()
|
CD3D11Device()
|
||||||
{
|
{
|
||||||
@@ -53,5 +56,8 @@ public:
|
|||||||
|
|
||||||
ComPtr<ID3D11DeviceContext4> GetContext() { return m_context; }
|
ComPtr<ID3D11DeviceContext4> GetContext() { return m_context; }
|
||||||
|
|
||||||
|
LUID GetAdapterLuid() const { return m_adapterLuid; }
|
||||||
|
|
||||||
bool IsSoftware() { return m_isSoftware; }
|
bool IsSoftware() { return m_isSoftware; }
|
||||||
|
bool IsVideo() const { return m_video; }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -432,7 +432,7 @@ bool CD3D12CommandQueue::InitTiming(ID3D12Device3 * device, UINT slotCount)
|
|||||||
bool CD3D12CommandQueue::Init(ID3D12Device3 * device,
|
bool CD3D12CommandQueue::Init(ID3D12Device3 * device,
|
||||||
D3D12_COMMAND_LIST_TYPE type, const WCHAR * name,
|
D3D12_COMMAND_LIST_TYPE type, const WCHAR * name,
|
||||||
CD3D12CommandSlot::CallbackMode callbackMode, UINT slotCount,
|
CD3D12CommandSlot::CallbackMode callbackMode, UINT slotCount,
|
||||||
bool enableTiming)
|
bool enableTiming, bool sharedFence)
|
||||||
{
|
{
|
||||||
if (!slotCount || slotCount > MAX_SLOTS)
|
if (!slotCount || slotCount > MAX_SLOTS)
|
||||||
{
|
{
|
||||||
@@ -455,7 +455,9 @@ bool CD3D12CommandQueue::Init(ID3D12Device3 * device,
|
|||||||
}
|
}
|
||||||
m_queue->SetName(name);
|
m_queue->SetName(name);
|
||||||
|
|
||||||
hr = device->CreateFence(0, D3D12_FENCE_FLAG_NONE,
|
const D3D12_FENCE_FLAGS fenceFlags = sharedFence ?
|
||||||
|
D3D12_FENCE_FLAG_SHARED : D3D12_FENCE_FLAG_NONE;
|
||||||
|
hr = device->CreateFence(0, fenceFlags,
|
||||||
IID_PPV_ARGS(&m_fence));
|
IID_PPV_ARGS(&m_fence));
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ class CD3D12CommandQueue
|
|||||||
|
|
||||||
bool Init(ID3D12Device3 * device, D3D12_COMMAND_LIST_TYPE type,
|
bool Init(ID3D12Device3 * device, D3D12_COMMAND_LIST_TYPE type,
|
||||||
const WCHAR * name, CD3D12CommandSlot::CallbackMode callbackMode,
|
const WCHAR * name, CD3D12CommandSlot::CallbackMode callbackMode,
|
||||||
UINT slotCount, bool enableTiming = false);
|
UINT slotCount, bool enableTiming = false, bool sharedFence = false);
|
||||||
void DeInit();
|
void DeInit();
|
||||||
|
|
||||||
CD3D12CommandSlot * Acquire(UINT slotIndex);
|
CD3D12CommandSlot * Acquire(UINT slotIndex);
|
||||||
|
|||||||
@@ -137,12 +137,12 @@ CD3D12Device::InitResult CD3D12Device::Init(
|
|||||||
|
|
||||||
if (!m_copyQueue.Init(m_device.Get(), D3D12_COMMAND_LIST_TYPE_COPY,
|
if (!m_copyQueue.Init(m_device.Get(), D3D12_COMMAND_LIST_TYPE_COPY,
|
||||||
L"Copy", m_indirectCopy ? CD3D12CommandSlot::NORMAL :
|
L"Copy", m_indirectCopy ? CD3D12CommandSlot::NORMAL :
|
||||||
CD3D12CommandSlot::FAST, 2, true))
|
CD3D12CommandSlot::FAST, 2, true, true))
|
||||||
return InitResult::FAILURE;
|
return InitResult::FAILURE;
|
||||||
|
|
||||||
if (m_computeEnabled &&
|
if (m_computeEnabled &&
|
||||||
!m_computeQueue.Init(m_device.Get(), D3D12_COMMAND_LIST_TYPE_COMPUTE,
|
!m_computeQueue.Init(m_device.Get(), D3D12_COMMAND_LIST_TYPE_COMPUTE,
|
||||||
L"Compute", CD3D12CommandSlot::FAST, 2))
|
L"Compute", CD3D12CommandSlot::FAST, 2, false, true))
|
||||||
return InitResult::FAILURE;
|
return InitResult::FAILURE;
|
||||||
|
|
||||||
DEBUG_INFO("Created CD3D12Device");
|
DEBUG_INFO("Created CD3D12Device");
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ struct CD3D12Device
|
|||||||
|
|
||||||
ComPtr<ID3D12Device3> GetDevice() { return m_device; }
|
ComPtr<ID3D12Device3> GetDevice() { return m_device; }
|
||||||
ComPtr<ID3D12Heap > GetTransportHeap() { return m_transportHeap; }
|
ComPtr<ID3D12Heap > GetTransportHeap() { return m_transportHeap; }
|
||||||
|
LUID GetAdapterLuid() const { return m_adapterLuid; }
|
||||||
bool IsIndirectCopy() const { return m_indirectCopy; }
|
bool IsIndirectCopy() const { return m_indirectCopy; }
|
||||||
|
|
||||||
CD3D12CommandSlot * GetCopySlot ();
|
CD3D12CommandSlot * GetCopySlot ();
|
||||||
|
|||||||
407
idd/LGIdd/d3d/CInteropPool.cpp
Normal file
407
idd/LGIdd/d3d/CInteropPool.cpp
Normal file
@@ -0,0 +1,407 @@
|
|||||||
|
/**
|
||||||
|
* Looking Glass
|
||||||
|
* Copyright © 2017-2026 The Looking Glass Authors
|
||||||
|
* https://looking-glass.io
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation; either version 2 of the License, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||||
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "d3d/CInteropPool.h"
|
||||||
|
|
||||||
|
#include "CDebug.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
using Microsoft::WRL::Wrappers::HandleT;
|
||||||
|
using Microsoft::WRL::Wrappers::HandleTraits::HANDLENullTraits;
|
||||||
|
|
||||||
|
static bool SameObject(IUnknown * left, IUnknown * right)
|
||||||
|
{
|
||||||
|
if (!left || !right)
|
||||||
|
return false;
|
||||||
|
ComPtr<IUnknown> leftId;
|
||||||
|
ComPtr<IUnknown> rightId;
|
||||||
|
return
|
||||||
|
SUCCEEDED(left->QueryInterface(IID_PPV_ARGS(&leftId))) &&
|
||||||
|
SUCCEEDED(right->QueryInterface(IID_PPV_ARGS(&rightId))) &&
|
||||||
|
leftId.Get() == rightId.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool SameDesc(const D3D12_RESOURCE_DESC& d12,
|
||||||
|
const D3D11_TEXTURE2D_DESC& d11)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
d12.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D &&
|
||||||
|
d12.Width == d11.Width &&
|
||||||
|
d12.Height == d11.Height &&
|
||||||
|
d12.DepthOrArraySize == d11.ArraySize &&
|
||||||
|
d12.MipLevels == d11.MipLevels &&
|
||||||
|
d12.Format == d11.Format &&
|
||||||
|
d12.SampleDesc.Count == d11.SampleDesc.Count &&
|
||||||
|
d12.SampleDesc.Quality == d11.SampleDesc.Quality &&
|
||||||
|
d11.Usage == D3D11_USAGE_DEFAULT &&
|
||||||
|
d11.CPUAccessFlags == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
D12SyncState D11Sync::State() const
|
||||||
|
{
|
||||||
|
if (ready)
|
||||||
|
return D12SyncState::READY;
|
||||||
|
if (!Valid())
|
||||||
|
return D12SyncState::FAILED;
|
||||||
|
const UINT64 completed = fence->GetCompletedValue();
|
||||||
|
if (completed == UINT64_MAX)
|
||||||
|
return D12SyncState::FAILED;
|
||||||
|
return completed >= value ?
|
||||||
|
D12SyncState::READY : D12SyncState::PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CD3D11Core
|
||||||
|
{
|
||||||
|
static const unsigned MAX_FENCES = 4;
|
||||||
|
|
||||||
|
struct View
|
||||||
|
{
|
||||||
|
uint64_t pool = 0;
|
||||||
|
ComPtr<ID3D12Resource> src;
|
||||||
|
ComPtr<ID3D11Texture2D> tex;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Fence
|
||||||
|
{
|
||||||
|
ComPtr<ID3D12Fence> src;
|
||||||
|
ComPtr<ID3D11Fence> fence;
|
||||||
|
};
|
||||||
|
|
||||||
|
mutable CSRWLock lock;
|
||||||
|
bool open = true;
|
||||||
|
bool failed = false;
|
||||||
|
uint64_t pool = 0;
|
||||||
|
UINT bind = 0;
|
||||||
|
std::shared_ptr<CD3D11Device> d11;
|
||||||
|
std::shared_ptr<CD3D12Device> d12;
|
||||||
|
ComPtr<ID3D11Device5> dev11;
|
||||||
|
ComPtr<ID3D12Device3> dev12;
|
||||||
|
View views[CTexPool::MAX_SLOTS];
|
||||||
|
Fence fences[MAX_FENCES];
|
||||||
|
|
||||||
|
void Stop()
|
||||||
|
{
|
||||||
|
CSRWExclusiveLock guard(lock);
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fail()
|
||||||
|
{
|
||||||
|
CSRWExclusiveLock guard(lock);
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexResult Error(HRESULT hr)
|
||||||
|
{
|
||||||
|
const HRESULT removed = dev12->GetDeviceRemovedReason();
|
||||||
|
const HRESULT removed11 = dev11->GetDeviceRemovedReason();
|
||||||
|
if (removed != S_OK || removed11 != S_OK || hr == E_OUTOFMEMORY)
|
||||||
|
{
|
||||||
|
const HRESULT reason = removed != S_OK ? removed :
|
||||||
|
(removed11 != S_OK ? removed11 : hr);
|
||||||
|
DEBUG_ERROR_HR(reason, "D3D11 texture interop failed");
|
||||||
|
failed = true;
|
||||||
|
return TexResult::FAILED;
|
||||||
|
}
|
||||||
|
DEBUG_WARN_HR(hr, "D3D11 texture interop is unavailable");
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexResult OpenView(const CFrameTex& frame,
|
||||||
|
ComPtr<ID3D11Texture2D>& texture)
|
||||||
|
{
|
||||||
|
if (frame.slot >= CTexPool::MAX_SLOTS)
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
|
||||||
|
View& view = views[frame.slot];
|
||||||
|
if (view.tex)
|
||||||
|
{
|
||||||
|
if (view.pool != frame.pool ||
|
||||||
|
!SameObject(view.src.Get(), frame.Get()))
|
||||||
|
{
|
||||||
|
failed = true;
|
||||||
|
return TexResult::FAILED;
|
||||||
|
}
|
||||||
|
texture = view.tex;
|
||||||
|
return TexResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE raw = nullptr;
|
||||||
|
const HRESULT create = dev12->CreateSharedHandle(frame.Get(), nullptr,
|
||||||
|
GENERIC_ALL, nullptr, &raw);
|
||||||
|
if (FAILED(create))
|
||||||
|
return Error(create);
|
||||||
|
HandleT<HANDLENullTraits> handle;
|
||||||
|
handle.Attach(raw);
|
||||||
|
|
||||||
|
ComPtr<ID3D11Texture2D> opened;
|
||||||
|
const HRESULT hr = dev11->OpenSharedResource1(handle.Get(),
|
||||||
|
IID_PPV_ARGS(&opened));
|
||||||
|
handle.Close();
|
||||||
|
if (FAILED(hr))
|
||||||
|
return Error(hr);
|
||||||
|
|
||||||
|
D3D11_TEXTURE2D_DESC desc11 = {};
|
||||||
|
opened->GetDesc(&desc11);
|
||||||
|
if (!SameDesc(frame.Get()->GetDesc(), desc11) ||
|
||||||
|
(desc11.BindFlags & bind) != bind)
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
|
||||||
|
view.pool = frame.pool;
|
||||||
|
view.src = frame.Get();
|
||||||
|
view.tex = opened;
|
||||||
|
texture = opened;
|
||||||
|
return TexResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexResult OpenFence(const D12Sync& sync, D11Sync& result)
|
||||||
|
{
|
||||||
|
ComPtr<ID3D12Device> owner;
|
||||||
|
if (!sync.Valid() ||
|
||||||
|
FAILED(sync.fence->GetDevice(IID_PPV_ARGS(&owner))) ||
|
||||||
|
!SameObject(owner.Get(), dev12.Get()))
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
|
||||||
|
const D12SyncState state = sync.State();
|
||||||
|
if (state == D12SyncState::FAILED)
|
||||||
|
{
|
||||||
|
failed = true;
|
||||||
|
return TexResult::FAILED;
|
||||||
|
}
|
||||||
|
if (state == D12SyncState::READY)
|
||||||
|
{
|
||||||
|
result.ready = true;
|
||||||
|
return TexResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < MAX_FENCES; ++i)
|
||||||
|
if (fences[i].fence &&
|
||||||
|
SameObject(fences[i].src.Get(), sync.fence.Get()))
|
||||||
|
{
|
||||||
|
result.fence = fences[i].fence;
|
||||||
|
result.value = sync.value;
|
||||||
|
return TexResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned free = MAX_FENCES;
|
||||||
|
for (unsigned i = 0; i < MAX_FENCES; ++i)
|
||||||
|
if (!fences[i].fence)
|
||||||
|
{
|
||||||
|
free = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (free == MAX_FENCES)
|
||||||
|
return TexResult::BUSY;
|
||||||
|
|
||||||
|
HANDLE raw = nullptr;
|
||||||
|
const HRESULT create = dev12->CreateSharedHandle(sync.fence.Get(),
|
||||||
|
nullptr, GENERIC_ALL, nullptr, &raw);
|
||||||
|
if (FAILED(create))
|
||||||
|
return Error(create);
|
||||||
|
HandleT<HANDLENullTraits> handle;
|
||||||
|
handle.Attach(raw);
|
||||||
|
|
||||||
|
ComPtr<ID3D11Fence> opened;
|
||||||
|
const HRESULT hr = dev11->OpenSharedFence(handle.Get(),
|
||||||
|
IID_PPV_ARGS(&opened));
|
||||||
|
handle.Close();
|
||||||
|
if (FAILED(hr))
|
||||||
|
return Error(hr);
|
||||||
|
|
||||||
|
fences[free].src = sync.fence;
|
||||||
|
fences[free].fence = opened;
|
||||||
|
result.fence = opened;
|
||||||
|
result.value = sync.value;
|
||||||
|
return TexResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexResult Get(const TexLease& src, D11Lease& lease)
|
||||||
|
{
|
||||||
|
const CFrameTex * frame = src.Get();
|
||||||
|
if (!frame ||
|
||||||
|
frame->profile.storage != FrameStorage::D3D12_TEXTURE ||
|
||||||
|
!frame->Shared() ||
|
||||||
|
frame->State() != D3D12_RESOURCE_STATE_COMMON ||
|
||||||
|
!frame->Get() ||
|
||||||
|
!frame->Sync().Valid())
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
|
||||||
|
ComPtr<ID3D12Device> owner;
|
||||||
|
if (FAILED(frame->Get()->GetDevice(IID_PPV_ARGS(&owner))) ||
|
||||||
|
!SameObject(owner.Get(), dev12.Get()))
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
|
||||||
|
CSRWExclusiveLock guard(lock);
|
||||||
|
if (!open || failed)
|
||||||
|
return TexResult::FAILED;
|
||||||
|
if (frame->Status() == D12SyncState::FAILED)
|
||||||
|
{
|
||||||
|
failed = true;
|
||||||
|
return TexResult::FAILED;
|
||||||
|
}
|
||||||
|
if (!pool)
|
||||||
|
pool = frame->pool;
|
||||||
|
else if (pool != frame->pool)
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
|
||||||
|
ComPtr<ID3D11Texture2D> texture;
|
||||||
|
TexResult result = OpenView(*frame, texture);
|
||||||
|
if (result != TexResult::OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
D11Sync sync;
|
||||||
|
result = OpenFence(frame->Sync(), sync);
|
||||||
|
if (result != TexResult::OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
const FrameProfile profile =
|
||||||
|
Frame::Store(frame->profile, FrameStorage::D3D11_TEXTURE);
|
||||||
|
lease = D11Lease(shared_from_this(), src, texture, sync, profile);
|
||||||
|
return TexResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Filled by Init after construction; avoids exposing ownership callbacks
|
||||||
|
// from cached COM objects.
|
||||||
|
std::weak_ptr<CD3D11Core> self;
|
||||||
|
|
||||||
|
std::shared_ptr<CD3D11Core> shared_from_this()
|
||||||
|
{
|
||||||
|
return self.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend class CInteropPool;
|
||||||
|
};
|
||||||
|
|
||||||
|
D11Lease::D11Lease(const std::shared_ptr<CD3D11Core>& core,
|
||||||
|
const TexLease& src, const ComPtr<ID3D11Texture2D>& tex,
|
||||||
|
const D11Sync& sync, const FrameProfile& profile) :
|
||||||
|
m_core(core),
|
||||||
|
m_src(src),
|
||||||
|
m_tex(tex),
|
||||||
|
m_sync(sync),
|
||||||
|
m_profile(profile)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TexResult D11Lease::Wait(ID3D11DeviceContext4 * context) const
|
||||||
|
{
|
||||||
|
if (!m_core || !m_src || !m_tex || !context || !m_sync.Valid())
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
|
||||||
|
ComPtr<ID3D11Device> owner;
|
||||||
|
context->GetDevice(owner.GetAddressOf());
|
||||||
|
if (!SameObject(owner.Get(), m_core->dev11.Get()))
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
|
||||||
|
const D12SyncState state = m_sync.State();
|
||||||
|
if (state == D12SyncState::FAILED)
|
||||||
|
{
|
||||||
|
m_core->Fail();
|
||||||
|
return TexResult::FAILED;
|
||||||
|
}
|
||||||
|
if (state == D12SyncState::READY)
|
||||||
|
return TexResult::OK;
|
||||||
|
|
||||||
|
const HRESULT hr = context->Wait(m_sync.fence.Get(), m_sync.value);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR_HR(hr, "Failed to queue the D3D11 producer wait");
|
||||||
|
m_core->Fail();
|
||||||
|
return TexResult::FAILED;
|
||||||
|
}
|
||||||
|
return TexResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D11Lease::Reset()
|
||||||
|
{
|
||||||
|
m_sync = D11Sync {};
|
||||||
|
m_tex.Reset();
|
||||||
|
m_src.Reset();
|
||||||
|
m_core.reset();
|
||||||
|
m_profile = FrameProfile {};
|
||||||
|
}
|
||||||
|
|
||||||
|
TexResult CInteropPool::Init(
|
||||||
|
const std::shared_ptr<CD3D11Device>& d11,
|
||||||
|
const std::shared_ptr<CD3D12Device>& d12, UINT bind)
|
||||||
|
{
|
||||||
|
if (!d11 || !d12 || !Frame::Same(d11->GetAdapterLuid(),
|
||||||
|
d12->GetAdapterLuid()))
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
|
||||||
|
ComPtr<ID3D11Device5> dev11 = d11->GetDevice();
|
||||||
|
ComPtr<ID3D12Device3> dev12 = d12->GetDevice();
|
||||||
|
if (!dev11 || !dev12)
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
|
||||||
|
std::shared_ptr<CD3D11Core> core;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
core = std::shared_ptr<CD3D11Core>(new (std::nothrow) CD3D11Core);
|
||||||
|
}
|
||||||
|
catch (const std::bad_alloc&)
|
||||||
|
{
|
||||||
|
return TexResult::FAILED;
|
||||||
|
}
|
||||||
|
if (!core)
|
||||||
|
return TexResult::FAILED;
|
||||||
|
core->d11 = d11;
|
||||||
|
core->d12 = d12;
|
||||||
|
core->dev11 = dev11;
|
||||||
|
core->dev12 = dev12;
|
||||||
|
core->bind = bind;
|
||||||
|
core->self = core;
|
||||||
|
|
||||||
|
std::shared_ptr<CD3D11Core> old;
|
||||||
|
{
|
||||||
|
CSRWExclusiveLock guard(m_lock);
|
||||||
|
old = std::move(m_core);
|
||||||
|
if (old)
|
||||||
|
old->Stop();
|
||||||
|
m_core = core;
|
||||||
|
}
|
||||||
|
return TexResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexResult CInteropPool::Get(const TexLease& src, D11Lease& lease)
|
||||||
|
{
|
||||||
|
if (lease)
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
|
||||||
|
std::shared_ptr<CD3D11Core> core;
|
||||||
|
{
|
||||||
|
CSRWSharedLock guard(m_lock);
|
||||||
|
core = m_core;
|
||||||
|
}
|
||||||
|
return core ? core->Get(src, lease) : TexResult::FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CInteropPool::Reset()
|
||||||
|
{
|
||||||
|
std::shared_ptr<CD3D11Core> core;
|
||||||
|
{
|
||||||
|
CSRWExclusiveLock guard(m_lock);
|
||||||
|
core = std::move(m_core);
|
||||||
|
if (core)
|
||||||
|
core->Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
102
idd/LGIdd/d3d/CInteropPool.h
Normal file
102
idd/LGIdd/d3d/CInteropPool.h
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
* Looking Glass
|
||||||
|
* Copyright © 2017-2026 The Looking Glass Authors
|
||||||
|
* https://looking-glass.io
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation; either version 2 of the License, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||||
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CSRWLock.h"
|
||||||
|
#include "capture/CFrameTex.h"
|
||||||
|
#include "d3d/CD3D11Device.h"
|
||||||
|
#include "d3d/CD3D12Device.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct CD3D11Core;
|
||||||
|
|
||||||
|
struct D11Sync
|
||||||
|
{
|
||||||
|
ComPtr<ID3D11Fence> fence;
|
||||||
|
UINT64 value = 0;
|
||||||
|
bool ready = false;
|
||||||
|
|
||||||
|
bool Valid() const { return ready || (fence && value); }
|
||||||
|
D12SyncState State() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A native D3D11 view of one immutable graph product. Keep the lease until
|
||||||
|
// the encoder's GPU completion, not merely until its submission returns.
|
||||||
|
class D11Lease
|
||||||
|
{
|
||||||
|
friend class CInteropPool;
|
||||||
|
friend struct CD3D11Core;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<CD3D11Core> m_core;
|
||||||
|
TexLease m_src;
|
||||||
|
ComPtr<ID3D11Texture2D> m_tex;
|
||||||
|
D11Sync m_sync;
|
||||||
|
FrameProfile m_profile;
|
||||||
|
|
||||||
|
D11Lease(const std::shared_ptr<CD3D11Core>& core, const TexLease& src,
|
||||||
|
const ComPtr<ID3D11Texture2D>& tex, const D11Sync& sync,
|
||||||
|
const FrameProfile& profile);
|
||||||
|
|
||||||
|
public:
|
||||||
|
D11Lease() = default;
|
||||||
|
D11Lease(const D11Lease&) = default;
|
||||||
|
D11Lease& operator=(const D11Lease&) = default;
|
||||||
|
D11Lease(D11Lease&&) noexcept = default;
|
||||||
|
D11Lease& operator=(D11Lease&&) noexcept = default;
|
||||||
|
|
||||||
|
explicit operator bool() const { return !!m_src && !!m_tex; }
|
||||||
|
ID3D11Texture2D * Get() const { return m_tex.Get(); }
|
||||||
|
const CFrameTex * Frame() const { return m_src.Get(); }
|
||||||
|
const FrameProfile& Profile() const { return m_profile; }
|
||||||
|
const D11Sync& Sync() const { return m_sync; }
|
||||||
|
D12SyncState Status() const { return m_sync.State(); }
|
||||||
|
|
||||||
|
// Orders only work subsequently submitted through this exact context.
|
||||||
|
// The context owner remains responsible for its thread serialization and
|
||||||
|
// for ordering any private encoder queue.
|
||||||
|
TexResult Wait(ID3D11DeviceContext4 * context) const;
|
||||||
|
void Reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Opens cached native D3D11 views of shareable D3D12 graph products. The
|
||||||
|
// pool never copies, transitions, or writes a product. Failures remain local
|
||||||
|
// to this interop route and cannot invalidate the source or sibling routes.
|
||||||
|
class CInteropPool
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
mutable CSRWLock m_lock;
|
||||||
|
std::shared_ptr<CD3D11Core> m_core;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CInteropPool() = default;
|
||||||
|
CInteropPool(const CInteropPool&) = delete;
|
||||||
|
CInteropPool& operator=(const CInteropPool&) = delete;
|
||||||
|
~CInteropPool() { Reset(); }
|
||||||
|
|
||||||
|
// bind is the minimum native D3D11 bind capability required by the future
|
||||||
|
// consumer. Unsupported capabilities reject this route without a copy.
|
||||||
|
TexResult Init(const std::shared_ptr<CD3D11Device>& d11,
|
||||||
|
const std::shared_ptr<CD3D12Device>& d12, UINT bind = 0);
|
||||||
|
TexResult Get(const TexLease& src, D11Lease& lease);
|
||||||
|
void Reset();
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user