[idd] rewrite to support DirectX12 copy

This commit is contained in:
Geoffrey McRae 2025-03-16 12:32:52 +00:00
parent 62c075cfb5
commit 8b198091ce
28 changed files with 1168 additions and 247 deletions

View File

@ -18,9 +18,10 @@
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Direct3DDevice.h"
#include "CD3D11Device.h"
#include "Debug.h"
HRESULT Direct3DDevice::Init()
HRESULT CD3D11Device::Init()
{
HRESULT hr = CreateDXGIFactory2(0, IID_PPV_ARGS(&m_factory));
if (FAILED(hr))
@ -29,18 +30,37 @@ HRESULT Direct3DDevice::Init()
hr = m_factory->EnumAdapterByLuid(m_adapterLuid, IID_PPV_ARGS(&m_adapter));
if (FAILED(hr))
return hr;
// only 11.1 supports DX12 interoperabillity
static const D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_1
};
D3D_FEATURE_LEVEL featureLevel;
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;
hr = D3D11CreateDevice(
m_adapter.Get(),
D3D_DRIVER_TYPE_UNKNOWN,
nullptr,
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
nullptr,
0,
D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_DEBUG,
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION,
&m_device,
nullptr,
&m_context);
&device,
&featureLevel,
&context);
if (FAILED(hr))
return hr;
DBGPRINT("Feature Level: 0x%x", featureLevel);
hr = device.As(&m_device);
if (FAILED(hr))
return hr;
hr = context.As(&m_context);
if (FAILED(hr))
return hr;

View File

@ -26,21 +26,29 @@
#include <dxgi1_5.h>
#include <d3d11_4.h>
struct Direct3DDevice
using namespace Microsoft::WRL;
struct CD3D11Device
{
Direct3DDevice(LUID adapterLuid) :
private:
LUID m_adapterLuid;
ComPtr<IDXGIFactory5 > m_factory;
ComPtr<IDXGIAdapter1 > m_adapter;
ComPtr<ID3D11Device5 > m_device;
ComPtr<ID3D11DeviceContext4> m_context;
public:
CD3D11Device(LUID adapterLuid) :
m_adapterLuid(adapterLuid) {};
Direct3DDevice()
CD3D11Device()
{
m_adapterLuid = LUID{};
}
HRESULT Init();
LUID m_adapterLuid;
Microsoft::WRL::ComPtr<IDXGIFactory5 > m_factory;
Microsoft::WRL::ComPtr<IDXGIAdapter1 > m_adapter;
Microsoft::WRL::ComPtr<ID3D11Device > m_device;
Microsoft::WRL::ComPtr<ID3D11DeviceContext> m_context;
ComPtr<ID3D11Device5> GetDevice() { return m_device; }
ComPtr<ID3D11DeviceContext4> GetContext() { return m_context; }
};

View File

@ -0,0 +1,115 @@
#include "CD3D12CommandQueue.h"
#include "Debug.h"
bool CD3D12CommandQueue::Init(ID3D12Device3 * device, D3D12_COMMAND_LIST_TYPE type, const WCHAR* name)
{
HRESULT hr;
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Type = type;
queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_HIGH;
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
hr = device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_queue));
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to create the CommandQueue (%ls)", name);
return false;
}
m_queue->SetName(name);
hr = device->CreateCommandAllocator(type, IID_PPV_ARGS(&m_allocator));
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to create the CommandAllocator (%ls)", name);
return false;
}
hr = device->CreateCommandList(0, type, m_allocator.Get(), NULL, IID_PPV_ARGS(&m_gfxList));
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to create the Graphics CommandList (%ls)", name);
return false;
}
m_gfxList->SetName(name);
m_cmdList = m_gfxList;
if (!m_cmdList)
{
DBGPRINT_HR(hr, "Failed to get the CommandList (%ls)", name);
return false;
}
hr = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence));
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to create the Fence (%ls)", name);
return false;
}
m_event.Attach(CreateEvent(NULL, FALSE, FALSE, NULL));
if (m_event.Get() == INVALID_HANDLE_VALUE)
{
DBGPRINT_HR(GetLastError(), "Failed to create the completion event (%ls)", name);
return false;
}
m_name = name;
m_fenceValue = 0;
DBGPRINT("Created CD3D12CommandQueue(%ls)", name);
return true;
}
bool CD3D12CommandQueue::Execute()
{
HRESULT hr = m_gfxList->Close();
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to close the command list (%ls)", m_name);
return false;
}
ID3D12CommandList * lists[] = { m_cmdList.Get() };
m_queue->ExecuteCommandLists(1, lists);
m_queue->Signal(m_fence.Get(), ++m_fenceValue);
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to set the fence signal (%ls)", m_name);
return false;
}
return true;
}
void CD3D12CommandQueue::Wait()
{
if (m_fence->GetCompletedValue() >= m_fenceValue)
return;
m_fence->SetEventOnCompletion(m_fenceValue, m_event.Get());
WaitForSingleObject(m_event.Get(), INFINITE);
}
bool CD3D12CommandQueue::Reset()
{
HRESULT hr;
hr = m_allocator->Reset();
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to reset the command allocator (%ls)", m_name);
return false;
}
hr = m_gfxList->Reset(m_allocator.Get(), NULL);
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to reset the graphics command list (%ls)", m_name);
return false;
}
return true;
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <Windows.h>
#include <wdf.h>
#include <wrl.h>
#include <d3d12.h>
using namespace Microsoft::WRL;
class CD3D12CommandQueue
{
private:
const WCHAR * m_name = nullptr;
ComPtr<ID3D12CommandQueue > m_queue;
ComPtr<ID3D12CommandAllocator > m_allocator;
ComPtr<ID3D12GraphicsCommandList> m_gfxList;
ComPtr<ID3D12CommandList > m_cmdList;
ComPtr<ID3D12Fence > m_fence;
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_event;
UINT64 m_fenceValue = 0;
public:
bool Init(ID3D12Device3 * device, D3D12_COMMAND_LIST_TYPE type, const WCHAR * name);
bool Execute();
void Wait();
bool Reset();
ComPtr<ID3D12CommandQueue > GetCmdQueue() { return m_queue; }
ComPtr<ID3D12GraphicsCommandList> GetGfxList() { return m_gfxList; }
};

169
idd/LGIdd/CD3D12Device.cpp Normal file
View File

@ -0,0 +1,169 @@
#include "CD3D12Device.h"
#include "Debug.h"
CD3D12Device::CD3D12Device(LUID adapterLuid) :
m_adapterLuid(adapterLuid),
m_debug(false),
m_indirectCopy(false)
{
if (m_debug)
{
HRESULT hr = D3D12GetDebugInterface(IID_PPV_ARGS(&m_dxDebug));
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to get the debug interface");
return;
}
m_dxDebug->EnableDebugLayer();
m_dxDebug->SetEnableGPUBasedValidation(TRUE);
m_dxDebug->SetEnableSynchronizedCommandQueueValidation(TRUE);
m_dxDebug->SetForceLegacyBarrierValidation(TRUE);
}
}
static void CALLBACK _D3D12DebugCallback(
D3D12_MESSAGE_CATEGORY category,
D3D12_MESSAGE_SEVERITY severity,
D3D12_MESSAGE_ID id,
LPCSTR description,
void *context
)
{
(void)context;
DBGPRINT("category:%d severity:%d id:%d desc:%s",
category,
severity,
id,
description);
}
bool CD3D12Device::Init(CIVSHMEM &ivshmem, UINT64 &alignSize)
{
reInit:
HRESULT hr;
hr = CreateDXGIFactory2(m_debug ? DXGI_CREATE_FACTORY_DEBUG : 0, IID_PPV_ARGS(&m_factory));
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to create the DXGI factory");
return false;
}
hr = m_factory->EnumAdapterByLuid(m_adapterLuid, IID_PPV_ARGS(&m_adapter));
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to enumerate the adapter");
return false;
}
hr = D3D12CreateDevice(m_adapter.Get(), D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(&m_device));
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to create the DirectX12 device");
return false;
}
if (m_debug)
{
hr = m_device.As(&m_infoQueue);
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to get the ID3D12InfoQueue1 interface");
//non-fatal do not exit
}
else
m_infoQueue->RegisterMessageCallback(
_D3D12DebugCallback, D3D12_MESSAGE_CALLBACK_FLAG_NONE, NULL, &m_callbackCookie);
}
if (!m_indirectCopy)
{
hr = m_device->OpenExistingHeapFromAddress(ivshmem.GetMem(), IID_PPV_ARGS(&m_ivshmemHeap));
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to open IVSHMEM as a D3D12Heap");
return false;
}
m_ivshmemHeap->SetName(L"IVSHMEM");
D3D12_HEAP_DESC heapDesc = m_ivshmemHeap->GetDesc();
alignSize = heapDesc.Alignment;
// test that the heap is usable
if (!HeapTest())
{
DBGPRINT("Unable to create resources in the IVSHMEM heap, falling back to indirect copy");
// failure often results in the device being removed and we need to completely reinit when this occurs
m_indirectCopy = true;
m_device.Reset();
m_adapter.Reset();
m_factory.Reset();
goto reInit;
}
DBGPRINT("Using IVSHMEM as a D3D12Heap");
}
if (!m_copyQueue.Init(m_device.Get(), D3D12_COMMAND_LIST_TYPE_COPY, L"Copy"))
return false;
//if (!m_computeQueue.Init(m_device.Get(), D3D12_COMMAND_LIST_TYPE_COMPUTE, L"Compute"))
//return false;
DBGPRINT("Created CD3D12Device");
return true;
}
void CD3D12Device::DeInit()
{
if (m_debug && m_infoQueue)
m_infoQueue->UnregisterMessageCallback(m_callbackCookie);
m_infoQueue.Reset();
}
bool CD3D12Device::HeapTest()
{
D3D12_RESOURCE_DESC desc = {};
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
desc.Width = 1048576;
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER;
HRESULT hr;
ComPtr<ID3D12Resource> resource;
hr = m_device->CreatePlacedResource(
m_ivshmemHeap.Get(),
0,
&desc,
D3D12_RESOURCE_STATE_COPY_DEST,
NULL,
IID_PPV_ARGS(&resource));
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to create the ivshmem ID3D12Resource");
return false;
}
resource->SetName(L"HeapTest");
/* the above may succeed even if there was a fault, as such we also need to check
* check if the device was removed */
hr = m_device->GetDeviceRemovedReason();
if (hr != S_OK)
{
DBGPRINT_HR(hr, "Device Removed");
return false;
}
return true;
}

48
idd/LGIdd/CD3D12Device.h Normal file
View File

@ -0,0 +1,48 @@
#pragma once
#include <Windows.h>
#include <wdf.h>
#include <wrl.h>
#include <dxgi1_5.h>
#include <d3d12.h>
#include "CIVSHMEM.h"
#include "CD3D12CommandQueue.h"
using namespace Microsoft::WRL;
struct CD3D12Device
{
private:
LUID m_adapterLuid;
bool m_debug;
bool m_indirectCopy;
ComPtr<ID3D12Debug6 > m_dxDebug;
ComPtr<ID3D12InfoQueue1> m_infoQueue;
DWORD m_callbackCookie;
ComPtr<IDXGIFactory5> m_factory;
ComPtr<IDXGIAdapter1> m_adapter;
ComPtr<ID3D12Device3> m_device;
ComPtr<ID3D12Heap > m_ivshmemHeap;
CD3D12CommandQueue m_copyQueue;
CD3D12CommandQueue m_computeQueue;
bool HeapTest();
public:
CD3D12Device(LUID adapterLUID);
~CD3D12Device() { DeInit(); }
bool Init(CIVSHMEM &ivshmem, UINT64 &alignSize);
void DeInit();
ComPtr<ID3D12Device3> GetDevice() { return m_device; }
ComPtr<ID3D12Heap > GetHeap() { return m_ivshmemHeap; }
bool IsIndirectCopy() { return m_indirectCopy; }
CD3D12CommandQueue& GetCopyQueue() { return m_copyQueue; }
CD3D12CommandQueue& GetComputeQueue() { return m_computeQueue; }
};

View File

@ -0,0 +1,31 @@
#include "CFrameBufferPool.h"
#include "CSwapChainProcessor.h"
#include <stdint.h>
void CFrameBufferPool::Init(CSwapChainProcessor * swapChain)
{
m_swapChain = swapChain;
}
void CFrameBufferPool::Reset()
{
for (int i = 0; i < ARRAYSIZE(m_buffers); ++i)
m_buffers[i].Reset();
}
CFrameBufferResource * CFrameBufferPool::Get(const CIndirectDeviceContext::PreparedFrameBuffer& buffer, size_t minSize)
{
if (buffer.frameIndex > ARRAYSIZE(m_buffers) - 1)
return nullptr;
CFrameBufferResource* fbr = &m_buffers[buffer.frameIndex];
if (!fbr->IsValid() || fbr->GetBase() != buffer.mem || fbr->GetSize() < minSize)
{
fbr->Reset();
if (!fbr->Init(m_swapChain, buffer.mem, minSize))
return nullptr;
}
return fbr;
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "CFrameBufferResource.h"
#include "CIndirectDeviceContext.h"
#include "common/KVMFR.h"
//class CSwapChainProcessor;
class CFrameBufferPool
{
CSwapChainProcessor * m_swapChain;
CFrameBufferResource m_buffers[LGMP_Q_FRAME_LEN];
public:
void Init(CSwapChainProcessor * swapChain);
void Reset();
CFrameBufferResource* CFrameBufferPool::Get(const CIndirectDeviceContext::PreparedFrameBuffer& buffer, size_t minSize);
};

View File

@ -0,0 +1,91 @@
#include "CFrameBufferResource.h"
#include "CSwapChainProcessor.h"
#include "Debug.h"
bool CFrameBufferResource::Init(CSwapChainProcessor * swapChain, uint8_t * base, size_t size)
{
if (size > swapChain->GetDevice()->GetMaxFrameSize())
{
DBGPRINT("Frame size of %lu is too large to fit in available shared ram");
return false;
}
// nothing to do if the resource already exists and is large enough
if (m_base == base && m_size >= size)
return true;
Reset();
D3D12_RESOURCE_DESC desc = {};
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Width = size;
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
HRESULT hr;
const WCHAR * resName;
if (swapChain->GetD3D12Device()->IsIndirectCopy())
{
DBGPRINT("Creating standard resource for %p", base);
D3D12_HEAP_PROPERTIES heapProps = {};
heapProps.Type = D3D12_HEAP_TYPE_READBACK;
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heapProps.CreationNodeMask = 1;
heapProps.VisibleNodeMask = 1;
hr = swapChain->GetD3D12Device()->GetDevice()->CreateCommittedResource(
&heapProps,
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_COPY_DEST,
NULL,
IID_PPV_ARGS(&m_res)
);
resName = L"STAGING";
}
else
{
DBGPRINT("Creating ivshmem resource for %p", base);
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER;
hr = swapChain->GetD3D12Device()->GetDevice()->CreatePlacedResource(
swapChain->GetD3D12Device()->GetHeap().Get(),
(uintptr_t)base - (uintptr_t)swapChain->GetDevice()->GetIVSHMEM().GetMem(),
&desc,
D3D12_RESOURCE_STATE_COPY_DEST,
NULL,
IID_PPV_ARGS(&m_res)
);
resName = L"IVSHMEM";
}
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to create the FrameBuffer ID3D12Resource");
return false;
}
m_res->SetName(resName);
m_base = base;
m_size = size;
m_valid = true;
return true;
}
void CFrameBufferResource::Reset()
{
m_base = nullptr;
m_size = 0;
m_res.Reset();
m_valid = false;
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <Windows.h>
#include <wdf.h>
#include <wrl.h>
#include <d3d12.h>
#include <stdint.h>
class CSwapChainProcessor;
using namespace Microsoft::WRL;
class CFrameBufferResource
{
private:
bool m_valid;
uint8_t * m_base;
size_t m_size;
ComPtr<ID3D12Resource> m_res;
public:
bool Init(CSwapChainProcessor * swapChain, uint8_t * base, size_t size);
void Reset();
bool IsValid() { return m_valid; }
uint8_t * GetBase() { return m_base; }
size_t GetSize() { return m_size; }
ComPtr<ID3D12Resource> Get() { return m_res; }
};

View File

@ -102,7 +102,7 @@ bool CIVSHMEM::Init()
{
DWORD bus = it->busAddr >> 32;
DWORD addr = it->busAddr & 0xFFFFFFFF;
DBGPRINT("IVSHMEM %u%c on bus 0x%lx, device 0x%lx, function 0x%lx\n",
DBGPRINT("IVSHMEM %u%c on bus 0x%lx, device 0x%lx, function 0x%lx",
i, i == shmDevice ? '*' : ' ', bus, addr >> 16, addr & 0xFFFF);
if (i == shmDevice)

View File

@ -40,29 +40,9 @@ static const struct LGMPQueueConfig POINTER_QUEUE_CONFIG =
1000 //subTimeout
};
CIndirectDeviceContext::~CIndirectDeviceContext()
{
if (m_lgmp == nullptr)
return;
if (m_lgmpTimer)
{
WdfTimerStop(m_lgmpTimer, TRUE);
m_lgmpTimer = nullptr;
}
for(int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
lgmpHostMemFree(&m_frameMemory[i]);
for (int i = 0; i < LGMP_Q_POINTER_LEN; ++i)
lgmpHostMemFree(&m_pointerMemory[i]);
for (int i = 0; i < POINTER_SHAPE_BUFFERS; ++i)
lgmpHostMemFree(&m_pointerShapeMemory[i]);
lgmpHostFree(&m_lgmp);
}
void CIndirectDeviceContext::InitAdapter()
{
if (!SetupLGMP())
if (!m_ivshmem.Init() || !m_ivshmem.Open())
return;
IDDCX_ADAPTER_CAPS caps = {};
@ -193,11 +173,15 @@ void CIndirectDeviceContext::FinishInit(UINT connectorIndex)
status = IddCxMonitorArrival(m_monitor, &out);
}
bool CIndirectDeviceContext::SetupLGMP()
bool CIndirectDeviceContext::SetupLGMP(size_t alignSize)
{
if (!m_ivshmem.Init() || !m_ivshmem.Open())
return false;
// this may get called multiple times as we need to delay calling it until
// we can determine the required alignment from the GPU in use
if (m_lgmp)
return true;
m_alignSize = alignSize;
std::stringstream ss;
{
KVMFR kvmfr = {};
@ -310,13 +294,13 @@ bool CIndirectDeviceContext::SetupLGMP()
}
m_maxFrameSize = lgmpHostMemAvail(m_lgmp);
m_maxFrameSize = (m_maxFrameSize -(CPlatformInfo::GetPageSize() - 1)) & ~(CPlatformInfo::GetPageSize() - 1);
m_maxFrameSize = (m_maxFrameSize -(m_alignSize - 1)) & ~(m_alignSize - 1);
m_maxFrameSize /= LGMP_Q_FRAME_LEN;
DBGPRINT("Max Frame Size: %u MiB\n", (unsigned int)(m_maxFrameSize / 1048576LL));
DBGPRINT("Max Frame Size: %u MiB", (unsigned int)(m_maxFrameSize / 1048576LL));
for (int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
if ((status = lgmpHostMemAllocAligned(m_lgmp, (uint32_t)m_maxFrameSize,
(uint32_t)CPlatformInfo::GetPageSize(), &m_frameMemory[i])) != LGMP_OK)
(uint32_t)m_alignSize, &m_frameMemory[i])) != LGMP_OK)
{
DBGPRINT("lgmpHostMemAllocAligned Failed (Frame): %s", lgmpStatusString(status));
return false;
@ -353,6 +337,26 @@ bool CIndirectDeviceContext::SetupLGMP()
return true;
}
void CIndirectDeviceContext::DeInitLGMP()
{
if (m_lgmp == nullptr)
return;
if (m_lgmpTimer)
{
WdfTimerStop(m_lgmpTimer, TRUE);
m_lgmpTimer = nullptr;
}
for (int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
lgmpHostMemFree(&m_frameMemory[i]);
for (int i = 0; i < LGMP_Q_POINTER_LEN; ++i)
lgmpHostMemFree(&m_pointerMemory[i]);
for (int i = 0; i < POINTER_SHAPE_BUFFERS; ++i)
lgmpHostMemFree(&m_pointerShapeMemory[i]);
lgmpHostFree(&m_lgmp);
}
void CIndirectDeviceContext::LGMPTimer()
{
LGMP_STATUS status;
@ -399,10 +403,22 @@ void CIndirectDeviceContext::LGMPTimer()
ResendCursor();
}
void CIndirectDeviceContext::SendFrame(int width, int height, int pitch, DXGI_FORMAT format, void* data)
//FIXME: this should not really be done here, this is a hack
#pragma warning(push)
#pragma warning(disable: 4200)
struct FrameBuffer
{
volatile uint32_t wp;
uint8_t data[0];
};
#pragma warning(pop)
CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrameBuffer(int width, int height, int pitch, DXGI_FORMAT format)
{
PreparedFrameBuffer result = {};
if (!m_lgmp || !m_frameQueue)
return;
return result;
if (m_width != width || m_height != height || m_pitch != pitch || m_format != format)
{
@ -413,13 +429,15 @@ void CIndirectDeviceContext::SendFrame(int width, int height, int pitch, DXGI_FO
++m_formatVer;
}
while (lgmpHostQueuePending(m_frameQueue) == LGMP_Q_FRAME_LEN)
Sleep(0);
if (++m_frameIndex == LGMP_Q_FRAME_LEN)
m_frameIndex = 0;
KVMFRFrame * fi = (KVMFRFrame *)lgmpHostMemPtr(m_frameMemory[m_frameIndex]);
// wait until there is room in the queue
while (lgmpHostQueuePending(m_frameQueue) == LGMP_Q_FRAME_LEN)
Sleep(0);
int bpp = 4;
switch (format)
{
@ -434,19 +452,9 @@ void CIndirectDeviceContext::SendFrame(int width, int height, int pitch, DXGI_FO
default:
DBGPRINT("Unsuppoted DXGI format");
return;
return result;
}
//FIXME: this should not really be done here, this is a hack
#pragma warning(push)
#pragma warning(disable: 4200)
struct FrameBuffer
{
volatile uint32_t wp;
uint8_t data[0];
};
#pragma warning(pop)
fi->formatVer = m_formatVer;
fi->frameSerial = m_frameSerial++;
fi->screenWidth = width;
@ -457,18 +465,30 @@ void CIndirectDeviceContext::SendFrame(int width, int height, int pitch, DXGI_FO
fi->frameHeight = height;
fi->stride = width * bpp;
fi->pitch = pitch;
fi->offset = (uint32_t)(CPlatformInfo::GetPageSize() - sizeof(FrameBuffer));
fi->offset = (uint32_t)(m_alignSize - sizeof(FrameBuffer));
fi->flags = 0;
fi->rotation = FRAME_ROT_0;
fi->damageRectsCount = 0;
FrameBuffer * fb = (FrameBuffer *)(((uint8_t*)fi) + fi->offset);
FrameBuffer* fb = (FrameBuffer*)(((uint8_t*)fi) + fi->offset);
fb->wp = 0;
lgmpHostQueuePost(m_frameQueue, 0, m_frameMemory[m_frameIndex]);
memcpy(fb->data, data, (size_t)height * (size_t)pitch);
fb->wp = height * pitch;
result.frameIndex = m_frameIndex;
result.mem = fb->data;
return result;
}
void CIndirectDeviceContext::FinalizeFrameBuffer()
{
if (!m_lgmp || !m_frameQueue)
return;
KVMFRFrame * fi = (KVMFRFrame*)lgmpHostMemPtr(m_frameMemory[m_frameIndex]);
FrameBuffer * fb = (FrameBuffer *)(((uint8_t*)fi) + fi->offset);
fb->wp = m_height * m_pitch;
}
void CIndirectDeviceContext::SendCursor(const IDARG_OUT_QUERY_HWCURSOR& info, const BYTE * data)
@ -504,7 +524,7 @@ void CIndirectDeviceContext::SendCursor(const IDARG_OUT_QUERY_HWCURSOR& info, co
if (info.CursorShapeInfo.CursorType != IDDCX_CURSOR_SHAPE_TYPE_UNINITIALIZED)
{
memcpy(cursor + 1, data,
(size_t)(info.CursorShapeInfo.Height * info.CursorShapeInfo.Pitch));
(size_t)info.CursorShapeInfo.Height * info.CursorShapeInfo.Pitch);
cursor->hx = (int8_t )info.CursorShapeInfo.XHot;
cursor->hy = (int8_t )info.CursorShapeInfo.YHot;

View File

@ -56,6 +56,7 @@ private:
bool m_cursorVisible = false;
int m_cursorX = 0, m_cursorY = 0;
size_t m_alignSize = 0;
size_t m_maxFrameSize = 0;
int m_frameIndex = 0;
uint32_t m_formatVer = 0;
@ -67,7 +68,7 @@ private:
int m_pitch = 0;
DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN;
bool SetupLGMP();
void DeInitLGMP();
void LGMPTimer();
void ResendCursor();
@ -75,14 +76,29 @@ public:
CIndirectDeviceContext(_In_ WDFDEVICE wdfDevice) :
m_wdfDevice(wdfDevice) {};
virtual ~CIndirectDeviceContext();
virtual ~CIndirectDeviceContext() { DeInitLGMP(); }
bool SetupLGMP(size_t alignSize);
void InitAdapter();
void FinishInit(UINT connectorIndex);
void SendFrame(int width, int height, int pitch, DXGI_FORMAT format, void* data);
size_t GetAlignSize() { return m_alignSize; }
size_t GetMaxFrameSize() { return m_maxFrameSize; }
struct PreparedFrameBuffer
{
unsigned frameIndex;
uint8_t* mem;
};
PreparedFrameBuffer PrepareFrameBuffer(int width, int height, int pitch, DXGI_FORMAT format);
void FinalizeFrameBuffer();
void SendCursor(const IDARG_OUT_QUERY_HWCURSOR & info, const BYTE * data);
CIVSHMEM &GetIVSHMEM() { return m_ivshmem; }
};
struct CIndirectDeviceContextWrapper

View File

@ -19,7 +19,7 @@
*/
#include "CIndirectMonitorContext.h"
#include "Direct3DDevice.h"
#include "CPlatformInfo.h"
#include "Debug.h"
CIndirectMonitorContext::CIndirectMonitorContext(_In_ IDDCX_MONITOR monitor, CIndirectDeviceContext * device) :
@ -28,7 +28,6 @@ CIndirectMonitorContext::CIndirectMonitorContext(_In_ IDDCX_MONITOR monitor, CIn
{
m_terminateEvent .Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr));
m_cursorDataEvent.Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr));
m_thread.Attach(CreateThread(nullptr, 0, _CursorThread, this, 0, nullptr));
m_shapeBuffer = new BYTE[512 * 512 * 4];
}
@ -42,14 +41,27 @@ CIndirectMonitorContext::~CIndirectMonitorContext()
void CIndirectMonitorContext::AssignSwapChain(IDDCX_SWAPCHAIN swapChain, LUID renderAdapter, HANDLE newFrameEvent)
{
m_swapChain.reset();
auto device = std::make_shared<Direct3DDevice>(renderAdapter);
if (FAILED(device->Init()))
m_dx11Device = std::make_shared<CD3D11Device>(renderAdapter);
if (FAILED(m_dx11Device->Init()))
{
WdfObjectDelete(swapChain);
return;
}
m_swapChain.reset(new CSwapChainProcessor(m_devContext, swapChain, device, newFrameEvent));
UINT64 alignSize = CPlatformInfo::GetPageSize();
m_dx12Device = std::make_shared<CD3D12Device>(renderAdapter);
if (!m_dx12Device->Init(m_devContext->GetIVSHMEM(), alignSize))
{
WdfObjectDelete(swapChain);
return;
}
if (!m_devContext->SetupLGMP(alignSize))
{
WdfObjectDelete(swapChain);
DBGPRINT("SetupLGMP failed");
return;
}
IDARG_IN_SETUP_HWCURSOR c = {};
c.CursorInfo.Size = sizeof(c.CursorInfo);
@ -60,12 +72,21 @@ void CIndirectMonitorContext::AssignSwapChain(IDDCX_SWAPCHAIN swapChain, LUID re
c.hNewCursorDataAvailable = m_cursorDataEvent.Get();
NTSTATUS status = IddCxMonitorSetupHardwareCursor(m_monitor, &c);
if (!NT_SUCCESS(status))
{
WdfObjectDelete(swapChain);
DBGPRINT("IddCxMonitorSetupHardwareCursor Failed: %08x", status);
return;
}
m_swapChain.reset(new CSwapChainProcessor(m_devContext, swapChain, m_dx11Device, m_dx12Device, newFrameEvent));
m_thread.Attach(CreateThread(nullptr, 0, _CursorThread, this, 0, nullptr));
}
void CIndirectMonitorContext::UnassignSwapChain()
{
m_swapChain.reset();
m_swapChain.reset();
m_dx11Device.reset();
m_dx12Device.reset();
}
DWORD CALLBACK CIndirectMonitorContext::_CursorThread(LPVOID arg)

View File

@ -34,6 +34,10 @@ class CIndirectMonitorContext
{
private:
IDDCX_MONITOR m_monitor;
std::shared_ptr<CD3D11Device> m_dx11Device;
std::shared_ptr<CD3D12Device> m_dx12Device;
CIndirectDeviceContext * m_devContext;
std::unique_ptr<CSwapChainProcessor> m_swapChain;

View File

@ -0,0 +1,127 @@
#include "CInteropResource.h"
#include "Debug.h"
bool CInteropResource::Init(std::shared_ptr<CD3D11Device> dx11Device, std::shared_ptr<CD3D12Device> dx12Device, ComPtr<ID3D11Texture2D> srcTex)
{
HRESULT hr;
D3D11_TEXTURE2D_DESC srcDesc;
srcTex->GetDesc(&srcDesc);
ComPtr<IDXGIResource1> rSrcTex;
hr = srcTex.As(&rSrcTex);
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to obtain the IDXGIResource1 interface");
return false;
}
HANDLE h;
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> sharedHandle;
hr = rSrcTex->CreateSharedHandle(NULL, DXGI_SHARED_RESOURCE_READ, NULL, &h);
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to create the shared handle");
return false;
}
sharedHandle.Attach(h);
ComPtr<ID3D12Resource> dst;
hr = dx12Device->GetDevice()->OpenSharedHandle(sharedHandle.Get(), IID_PPV_ARGS(&dst));
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to open the D3D12Resource from the handle");
return false;
}
sharedHandle.Close();
ComPtr<ID3D11Fence> d11Fence;
hr = dx11Device->GetDevice()->CreateFence(0, D3D11_FENCE_FLAG_SHARED, IID_PPV_ARGS(&d11Fence));
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to create the d3d11 fence");
return false;
}
hr = d11Fence->CreateSharedHandle(NULL, GENERIC_ALL, NULL, &h);
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to create the d3d11 fence shared handle");
return false;
}
sharedHandle.Attach(h);
ComPtr<ID3D12Fence> d12Fence;
hr = dx12Device->GetDevice()->OpenSharedHandle(sharedHandle.Get(), IID_PPV_ARGS(&d12Fence));
if (FAILED(hr))
{
DBGPRINT_HR(hr, "Failed to open the D3D12Fence from the handle");
return false;
}
sharedHandle.Close();
m_dx11Device = dx11Device;
m_dx12Device = dx12Device;
memcpy(&m_format, &srcDesc, sizeof(m_format));
m_srcTex = srcTex.Get();
m_d12Res = dst;
m_d11Fence = d11Fence;
m_d12Fence = d12Fence;
m_fenceValue = 0;
m_ready = true;
return true;
}
void CInteropResource::Reset()
{
m_ready = false;
m_fenceValue = 0;
m_d12Fence.Reset();
m_d11Fence.Reset();
m_d12Res .Reset();
m_srcTex = NULL;
memset(&m_format, 0, sizeof(m_format));
m_dx12Device.reset();
m_dx11Device.reset();
}
bool CInteropResource::Compare(const ComPtr<ID3D11Texture2D>& srcTex)
{
if (srcTex.Get() != m_srcTex)
return false;
D3D11_TEXTURE2D_DESC format;
srcTex->GetDesc(&format);
return
m_format.Width == format.Width &&
m_format.Height == format.Height &&
m_format.Format == format.Format;
}
void CInteropResource::Signal()
{
++m_fenceValue;
m_dx11Device->GetContext()->Signal(m_d11Fence.Get(), m_fenceValue);
}
void CInteropResource::Sync(CD3D12CommandQueue& queue)
{
if (m_d11Fence->GetCompletedValue() < m_fenceValue)
queue.GetCmdQueue()->Wait(m_d12Fence.Get(), m_fenceValue);
}
void CInteropResource::SetFullDamage()
{
m_dirtyRects[0].left = 0;
m_dirtyRects[0].top = 0;
m_dirtyRects[0].right = m_format.Width;
m_dirtyRects[0].bottom = m_format.Height;
m_nbDirtyRects = 1;
}

View File

@ -0,0 +1,48 @@
#pragma once
#include <Windows.h>
#include <wdf.h>
#include <wrl.h>
#include <memory>
#include "CD3D11Device.h"
#include "CD3D12Device.h"
#include "CD3D12CommandQueue.h"
using namespace Microsoft::WRL;
#define LG_MAX_DIRTY_RECTS 256
class CInteropResource
{
private:
std::shared_ptr<CD3D11Device> m_dx11Device;
std::shared_ptr<CD3D12Device> m_dx12Device;
/* this value is likely released, it is only used to check if the texture supplied
is different, do not rely on it pointing to valid memory */
void * m_srcTex;
ComPtr<ID3D12Resource > m_d12Res;
D3D11_TEXTURE2D_DESC m_format;
ComPtr<ID3D11Fence > m_d11Fence;
ComPtr<ID3D12Fence > m_d12Fence;
UINT64 m_fenceValue;
bool m_ready;
RECT m_dirtyRects[LG_MAX_DIRTY_RECTS];
unsigned m_nbDirtyRects;
public:
bool Init(std::shared_ptr<CD3D11Device> dx11Device, std::shared_ptr<CD3D12Device> dx12Device, ComPtr<ID3D11Texture2D> srcTex);
void Reset();
bool IsReady() { return m_ready; }
bool Compare(const ComPtr<ID3D11Texture2D>& srcTex);
void Signal();
void Sync(CD3D12CommandQueue& queue);
void SetFullDamage();
const ComPtr<ID3D12Resource>& GetRes() { return m_d12Res; }
const D3D11_TEXTURE2D_DESC& GetFormat() { return m_format; }
};

View File

@ -0,0 +1,47 @@
#include "CInteropResourcePool.h"
#include "Debug.h"
void CInteropResourcePool::Init(std::shared_ptr<CD3D11Device> dx11Device, std::shared_ptr<CD3D12Device> dx12Device)
{
Reset();
m_dx11Device = dx11Device;
m_dx12Device = dx12Device;
}
void CInteropResourcePool::Reset()
{
for (unsigned i = 0; i < POOL_SIZE; ++i)
m_pool[i].Reset();
m_dx11Device.reset();
m_dx12Device.reset();
}
CInteropResource* CInteropResourcePool::Get(ComPtr<ID3D11Texture2D> srcTex)
{
CInteropResource * res;
unsigned freeSlot = POOL_SIZE;
for (unsigned i = 0; i < POOL_SIZE; ++i)
{
res = &m_pool[i];
if (!res->IsReady())
{
freeSlot = min(freeSlot, i);
continue;
}
if (res->Compare(srcTex))
return res;
}
if (freeSlot == POOL_SIZE)
{
DBGPRINT("Interop Resouce Pool Full");
return nullptr;
}
res = &m_pool[freeSlot];
if (!res->Init(m_dx11Device, m_dx12Device, srcTex))
return nullptr;
return res;
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <Windows.h>
#include <wdf.h>
#include <wrl.h>
#include <d3d11_4.h>
#include "CInteropResource.h"
using namespace Microsoft::WRL;
#define POOL_SIZE 10
class CInteropResourcePool
{
private:
CInteropResource m_pool[POOL_SIZE];
std::shared_ptr<CD3D11Device> m_dx11Device;
std::shared_ptr<CD3D12Device> m_dx12Device;
public:
void Init(std::shared_ptr<CD3D11Device> dx11Device, std::shared_ptr<CD3D12Device> dx12Device);
void Reset();
CInteropResource* Get(ComPtr<ID3D11Texture2D> srcTex);
};

View File

@ -35,15 +35,18 @@
#define UNLOCK_ST(st) UNLOCK((st).lock);
CSwapChainProcessor::CSwapChainProcessor(CIndirectDeviceContext* devContext, IDDCX_SWAPCHAIN hSwapChain,
std::shared_ptr<Direct3DDevice> device, HANDLE newFrameEvent) :
std::shared_ptr<CD3D11Device> dx11Device, std::shared_ptr<CD3D12Device> dx12Device, HANDLE newFrameEvent) :
m_devContext(devContext),
m_hSwapChain(hSwapChain),
m_device(device),
m_dx11Device(dx11Device),
m_dx12Device(dx12Device),
m_newFrameEvent(newFrameEvent)
{
{
m_resPool.Init(dx11Device, dx12Device);
m_fbPool.Init(this);
m_terminateEvent.Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr));
m_thread[0].Attach(CreateThread(nullptr, 0, _SwapChainThread, this, 0, nullptr));
m_thread[1].Attach(CreateThread(nullptr, 0, _FrameThread , this, 0, nullptr));
}
CSwapChainProcessor::~CSwapChainProcessor()
@ -54,12 +57,8 @@ CSwapChainProcessor::~CSwapChainProcessor()
if (m_thread[1].Get())
WaitForSingleObject(m_thread[1].Get(), INFINITE);
for(int i = 0; i < STAGING_TEXTURES; ++i)
if (m_cpuTex[i].map.pData)
{
m_device->m_context->Unmap(m_cpuTex[i].tex.Get(), 0);
m_cpuTex[i].map.pData = nullptr;
}
m_resPool.Reset();
m_fbPool.Reset();
}
DWORD CALLBACK CSwapChainProcessor::_SwapChainThread(LPVOID arg)
@ -84,8 +83,8 @@ void CSwapChainProcessor::SwapChainThread()
void CSwapChainProcessor::SwapChainThreadCore()
{
Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
HRESULT hr = m_device->m_device.As(&dxgiDevice);
ComPtr<IDXGIDevice> dxgiDevice;
HRESULT hr = m_dx11Device->GetDevice().As(&dxgiDevice);
if (FAILED(hr))
{
DBGPRINT("Failed to get the dxgiDevice");
@ -109,10 +108,7 @@ void CSwapChainProcessor::SwapChainThreadCore()
IDARG_IN_SWAPCHAINSETDEVICE setDevice = {};
setDevice.pDevice = dxgiDevice.Get();
LOCK_CONTEXT();
hr = IddCxSwapChainSetDevice(m_hSwapChain, &setDevice);
UNLOCK_CONTEXT();
if (FAILED(hr))
{
DBGPRINT("IddCxSwapChainSetDevice Failed (%08x)", hr);
@ -122,15 +118,11 @@ void CSwapChainProcessor::SwapChainThreadCore()
UINT lastFrameNumber = 0;
for (;;)
{
ComPtr<IDXGIResource> acquiredBuffer;
IDARG_OUT_RELEASEANDACQUIREBUFFER buffer = {};
LOCK_CONTEXT();
hr = IddCxSwapChainReleaseAndAcquireBuffer(m_hSwapChain, &buffer);
if (hr == E_PENDING)
{
UNLOCK_CONTEXT();
HANDLE waitHandles[] =
{
m_newFrameEvent,
@ -152,22 +144,15 @@ void CSwapChainProcessor::SwapChainThreadCore()
if (buffer.MetaData.PresentationFrameNumber != lastFrameNumber)
{
lastFrameNumber = buffer.MetaData.PresentationFrameNumber;
if (m_copyCount < STAGING_TEXTURES)
{
acquiredBuffer.Attach(buffer.MetaData.pSurface);
SwapChainNewFrame(acquiredBuffer);
acquiredBuffer.Reset();
}
SwapChainNewFrame(buffer.MetaData.pSurface);
}
hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain);
UNLOCK_CONTEXT();
if (FAILED(hr))
break;
}
else
{
UNLOCK_CONTEXT();
break;
}
}
@ -175,119 +160,78 @@ void CSwapChainProcessor::SwapChainThreadCore()
void CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer)
{
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture;
if (FAILED(acquiredBuffer->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&texture)))
ComPtr<ID3D11Texture2D> texture;
HRESULT hr = acquiredBuffer.As(&texture);
if (FAILED(hr))
{
DBGPRINT("Failed to obtain the ID3D11Texture2D from the acquiredBuffer");
DBGPRINT_HR(hr, "Failed to obtain the ID3D11Texture2D from the acquiredBuffer");
return;
}
D3D11_TEXTURE2D_DESC desc;
texture->GetDesc(&desc);
StagingTexture &st = m_cpuTex[m_texWIndex];
if (st.map.pData)
CInteropResource * srcRes = m_resPool.Get(texture);
if (!srcRes)
{
m_device->m_context->Unmap(st.tex.Get(), 0);
st.map.pData = nullptr;
DBGPRINT("Failed to get a CInteropResource from the pool");
return;
}
if (!SetupStagingTexture(st, desc.Width, desc.Height, desc.Format))
/**
* Even though we have not performed any copy/draw operations we still need to
* use a fence. Because we share this texture with DirectX12 it is able to
* read from it before the desktop duplication API has finished updating it.
*/
srcRes->Signal();
//FIXME: handle dirty rects
srcRes->SetFullDamage();
auto buffer = m_devContext->PrepareFrameBuffer(
srcRes->GetFormat().Width,
srcRes->GetFormat().Height,
srcRes->GetFormat().Width * 4,
srcRes->GetFormat().Format);
if (!buffer.mem)
return;
m_device->m_context->CopyResource(st.tex.Get(), texture.Get());
CFrameBufferResource * fbRes = m_fbPool.Get(buffer,
((size_t)srcRes->GetFormat().Width * 4) * srcRes->GetFormat().Height);
InterlockedAdd(&m_copyCount, 1);
if (++m_texWIndex == STAGING_TEXTURES)
m_texWIndex = 0;
}
DWORD CALLBACK CSwapChainProcessor::_FrameThread(LPVOID arg)
{
reinterpret_cast<CSwapChainProcessor*>(arg)->FrameThread();
return 0;
}
void CSwapChainProcessor::FrameThread()
{
for(;;)
if (!fbRes)
{
if (WaitForSingleObject(m_terminateEvent.Get(), 0) == WAIT_OBJECT_0)
break;
if (!m_copyCount)
{
Sleep(0);
continue;
}
StagingTexture & st = m_cpuTex[m_texRIndex];
LOCK(st);
LOCK_CONTEXT();
HRESULT status = m_device->m_context->Map(st.tex.Get(), 0, D3D11_MAP_READ,
D3D11_MAP_FLAG_DO_NOT_WAIT, &st.map);
UNLOCK_CONTEXT();
if (FAILED(status))
{
UNLOCK(st);
if (status == DXGI_ERROR_WAS_STILL_DRAWING)
continue;
DBGPRINT("Failed to map staging texture");
InterlockedAdd(&m_copyCount, -1);
if (++m_texRIndex == STAGING_TEXTURES)
m_texRIndex = 0;
continue;
}
m_devContext->SendFrame(st.width, st.height, st.map.RowPitch, st.format, st.map.pData);
InterlockedAdd(&m_copyCount, -1);
m_lastIndex = m_texRIndex;
if (++m_texRIndex == STAGING_TEXTURES)
m_texRIndex = 0;
UNLOCK(st);
DBGPRINT("Failed to get a CFrameBufferResource from the pool");
return;
}
}
D3D12_TEXTURE_COPY_LOCATION srcLoc = {};
srcLoc.pResource = srcRes->GetRes().Get();
srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
srcLoc.SubresourceIndex = 0;
bool CSwapChainProcessor::SetupStagingTexture(StagingTexture & st, int width, int height, DXGI_FORMAT format)
{
if (st.width == width && st.height == height && st.format == format)
return true;
D3D12_TEXTURE_COPY_LOCATION dstLoc = {};
dstLoc.pResource = fbRes->Get().Get();
dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
dstLoc.PlacedFootprint.Offset = 0;
dstLoc.PlacedFootprint.Footprint.Format = srcRes->GetFormat().Format;
dstLoc.PlacedFootprint.Footprint.Width = srcRes->GetFormat().Width;
dstLoc.PlacedFootprint.Footprint.Height = srcRes->GetFormat().Height;
dstLoc.PlacedFootprint.Footprint.Depth = 1;
dstLoc.PlacedFootprint.Footprint.RowPitch = srcRes->GetFormat().Width * 4; //FIXME
st.tex.Reset();
st.width = width;
st.height = height;
st.format = format;
srcRes->Sync(m_dx12Device->GetCopyQueue());
m_dx12Device->GetCopyQueue().GetGfxList()->CopyTextureRegion(
&dstLoc, 0, 0, 0, &srcLoc, NULL);
D3D11_TEXTURE2D_DESC desc = {};
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_STAGING;
desc.Format = format;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.MiscFlags = 0;
m_dx12Device->GetCopyQueue().Execute();
m_dx12Device->GetCopyQueue().Wait();
m_dx12Device->GetCopyQueue().Reset();
if (FAILED(m_device->m_device->CreateTexture2D(&desc, nullptr, &st.tex)))
{
DBGPRINT("Failed to create staging texture");
return false;
}
return true;
m_devContext->FinalizeFrameBuffer();
}
void CSwapChainProcessor::ResendLastFrame()
{
/*
LOCK_CONTEXT()
StagingTexture & st = m_cpuTex[m_lastIndex];
LOCK_ST(st);
@ -301,4 +245,5 @@ void CSwapChainProcessor::ResendLastFrame()
m_devContext->SendFrame(st.width, st.height, st.map.RowPitch, st.format, st.map.pData);
UNLOCK_ST(st);
*/
}

View File

@ -20,8 +20,11 @@
#pragma once
#include "Direct3DDevice.h"
#include "CD3D11Device.h"
#include "CD3D12Device.h"
#include "CIndirectDeviceContext.h"
#include "CInteropResourcePool.h"
#include "CFrameBufferPool.h"
#include <Windows.h>
#include <wrl.h>
@ -37,45 +40,29 @@ class CSwapChainProcessor
private:
CIndirectDeviceContext * m_devContext;
IDDCX_SWAPCHAIN m_hSwapChain;
std::shared_ptr<Direct3DDevice> m_device;
std::shared_ptr<CD3D11Device> m_dx11Device;
std::shared_ptr<CD3D12Device> m_dx12Device;
HANDLE m_newFrameEvent;
CInteropResourcePool m_resPool;
CFrameBufferPool m_fbPool;
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_thread[2];
Wrappers::Event m_terminateEvent;
static DWORD CALLBACK _SwapChainThread(LPVOID arg);
static DWORD CALLBACK _FrameThread(LPVOID arg);
void SwapChainThread();
void SwapChainThreadCore();
void SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer);
void FrameThread();
struct StagingTexture
{
volatile LONG lock = 0;
int width = 0;
int height = 0;
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
Microsoft::WRL::ComPtr<ID3D11Texture2D> tex;
D3D11_MAPPED_SUBRESOURCE map = {};
};
StagingTexture m_cpuTex[STAGING_TEXTURES] = {};
volatile LONG m_copyCount = 0;
volatile LONG m_contextLock = 0;
int m_texRIndex = 0;
int m_texWIndex = 0;
int m_lastIndex = 0;
bool SetupStagingTexture(StagingTexture & st, int width, int height, DXGI_FORMAT format);
public:
CSwapChainProcessor(CIndirectDeviceContext * devContext, IDDCX_SWAPCHAIN hSwapChain,
std::shared_ptr<Direct3DDevice> device, HANDLE newFrameEvent);
std::shared_ptr<CD3D11Device> dx11Device, std::shared_ptr<CD3D12Device> dx12Device, HANDLE newFrameEvent);
~CSwapChainProcessor();
CIndirectDeviceContext * GetDevice() { return m_devContext; }
std::shared_ptr<CD3D12Device> GetD3D12Device() { return m_dx12Device; }
void ResendLastFrame();
};

View File

@ -22,18 +22,21 @@
#include <malloc.h>
#include <strsafe.h>
#include "Debug.h"
/* credit: https://stackoverflow.com/questions/29049686/is-there-a-better-way-to-pass-formatted-output-to-outputdebugstring */
VOID _DBGPRINT(PCSTR kwszFunction, INT iLineNumber, LPCSTR kszDebugFormatString, ...) \
VOID _DBGPRINT(PCSTR kwszFunction, INT iLineNumber, LPCSTR kszDebugFormatString, ...)
{
INT cbFormatString = 0;
va_list args;
PCHAR szDebugString = NULL;
size_t st_Offset = 0;
size_t stOffset = 0;
va_start(args, kszDebugFormatString);
cbFormatString = _scprintf("[%s:%d] ", kwszFunction, iLineNumber) * sizeof(CHAR);
cbFormatString += _vscprintf(kszDebugFormatString, args) * sizeof(CHAR) + 2;
cbFormatString = _scprintf("[%s:%d] ", kwszFunction, iLineNumber);
cbFormatString += _vscprintf(kszDebugFormatString, args);
cbFormatString += 2;
/* Depending on the size of the format string, allocate space on the stack or the heap. */
szDebugString = (PCHAR)_malloca(cbFormatString);
@ -42,11 +45,64 @@ VOID _DBGPRINT(PCSTR kwszFunction, INT iLineNumber, LPCSTR kszDebugFormatString,
/* Populate the buffer with the contents of the format string. */
StringCbPrintfA(szDebugString, cbFormatString, "[%s:%d] ", kwszFunction, iLineNumber);
StringCbLengthA(szDebugString, cbFormatString, &st_Offset);
StringCbVPrintfA(&szDebugString[st_Offset / sizeof(CHAR)], cbFormatString - st_Offset, kszDebugFormatString, args);
StringCbLengthA(szDebugString, cbFormatString, &stOffset);
StringCbVPrintfA(&szDebugString[stOffset], cbFormatString - stOffset, kszDebugFormatString, args);
OutputDebugStringA(szDebugString);
_freea(szDebugString);
va_end(args);
}
VOID _DBGPRINT_HR(PCSTR kwszFunction, INT iLineNumber, LPCSTR kszDebugFormatString, HRESULT status, ...)
{
char * buffer;
if (!FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
status,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(char*)&buffer,
1024,
NULL
))
{
DBGPRINT("FormatMessage failed with code 0x%08x", GetLastError());
return;
}
INT cbFormatString = 0;
va_list args;
PCHAR szDebugString = NULL;
size_t stOffset = 0;
va_start(args, kszDebugFormatString);
cbFormatString = _scprintf("[%s:%d] ", kwszFunction, iLineNumber);
cbFormatString += _vscprintf(kszDebugFormatString, args);
cbFormatString += 2 + 4 + (int)strlen(buffer);
/* Depending on the size of the format string, allocate space on the stack or the heap. */
szDebugString = (PCHAR)_malloca(cbFormatString);
if (!szDebugString)
{
va_end(args);
return;
}
/* Populate the buffer with the contents of the format string. */
StringCbPrintfA(szDebugString, cbFormatString, "[%s:%d] ", kwszFunction, iLineNumber);
StringCbLengthA(szDebugString, cbFormatString, &stOffset);
StringCbVPrintfA(&szDebugString[stOffset], cbFormatString - stOffset, kszDebugFormatString, args);
/* append the formatted error */
StringCbLengthA(szDebugString, cbFormatString, &stOffset);
StringCbPrintfA(&szDebugString[stOffset], cbFormatString - stOffset, " (%s)", buffer);
OutputDebugStringA(szDebugString);
_freea(szDebugString);
va_end(args);
LocalFree(buffer);
}

View File

@ -25,4 +25,8 @@
VOID _DBGPRINT(PCSTR kszFunction, INT iLineNumber, LPCSTR kszDebugFormatString, ...);
#define DBGPRINT(kszDebugFormatString, ...) \
_DBGPRINT(__FUNCTION__, __LINE__, kszDebugFormatString, __VA_ARGS__)
_DBGPRINT(__FUNCTION__, __LINE__, kszDebugFormatString "\n", __VA_ARGS__)
VOID _DBGPRINT_HR(PCSTR kwszFunction, INT iLineNumber, LPCSTR kszDebugFormatString, HRESULT status, ...);
#define DBGPRINT_HR(status, kszDebugFormatString, ...) \
_DBGPRINT_HR(__FUNCTION__, __LINE__, kszDebugFormatString "\n", status, __VA_ARGS__)

View File

@ -140,7 +140,8 @@ NTSTATUS LGIddMonitorQueryTargetModes(IDDCX_MONITOR monitor, const IDARG_IN_QUER
NTSTATUS LGIddMonitorAssignSwapChain(IDDCX_MONITOR monitor, const IDARG_IN_SETSWAPCHAIN* inArgs)
{
auto * wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(monitor);
wrapper->context->AssignSwapChain(inArgs->hSwapChain, inArgs->RenderAdapterLuid, inArgs->hNextSurfaceAvailable);
wrapper->context->AssignSwapChain(
inArgs->hSwapChain, inArgs->RenderAdapterLuid, inArgs->hNextSurfaceAvailable);
return STATUS_SUCCESS;
}

View File

@ -46,16 +46,19 @@ NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING Reg
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "WdfDriverCreate failed %!STATUS!", status);
#if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0
WPP_CLEANUP();
#else
WPP_CLEANUP(DriverObject);
#endif
return status;
goto fail;
}
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
return status;
fail:
#if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0
WPP_CLEANUP();
#else
WPP_CLEANUP(DriverObject);
#endif
return status;
}
NTSTATUS LGIddEvtDeviceAdd(_In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit)

View File

@ -38,24 +38,36 @@
<None Include="cpp.hint" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="CD3D12CommandQueue.cpp" />
<ClCompile Include="CFrameBufferPool.cpp" />
<ClCompile Include="CFrameBufferResource.cpp" />
<ClCompile Include="CIndirectDeviceContext.cpp" />
<ClCompile Include="CIndirectMonitorContext.cpp" />
<ClCompile Include="CInteropResourcePool.cpp" />
<ClCompile Include="CInteropResource.cpp" />
<ClCompile Include="CIVSHMEM.cpp" />
<ClCompile Include="CPlatformInfo.cpp" />
<ClCompile Include="CSwapChainProcessor.cpp" />
<ClCompile Include="CD3D12Device.cpp" />
<ClCompile Include="Debug.cpp" />
<ClCompile Include="Device.cpp" />
<ClCompile Include="Direct3DDevice.cpp" />
<ClCompile Include="CD3D11Device.cpp" />
<ClCompile Include="Driver.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="CD3D12CommandQueue.h" />
<ClInclude Include="CFrameBufferPool.h" />
<ClInclude Include="CFrameBufferResource.h" />
<ClInclude Include="CIndirectMonitorContext.h" />
<ClInclude Include="CInteropResourcePool.h" />
<ClInclude Include="CInteropResource.h" />
<ClInclude Include="CIVSHMEM.h" />
<ClInclude Include="CPlatformInfo.h" />
<ClInclude Include="CSwapChainProcessor.h" />
<ClInclude Include="CD3D12Device.h" />
<ClInclude Include="Debug.h" />
<ClInclude Include="Device.h" />
<ClInclude Include="Direct3DDevice.h" />
<ClInclude Include="CD3D11Device.h" />
<ClInclude Include="Driver.h" />
<ClInclude Include="CIndirectDeviceContext.h" />
<ClInclude Include="Public.h" />
@ -257,7 +269,7 @@
<AdditionalIncludeDirectories>$(ProjectDir)..\..\repos\LGMP\lgmp\include;$(ProjectDir)..\..\vendor;$(ProjectDir)..\..\common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;d3d12.lib</AdditionalDependencies>
</Link>
<DriverSign>
<FileDigestAlgorithm>SHA1</FileDigestAlgorithm>
@ -272,7 +284,7 @@
<AdditionalIncludeDirectories>$(ProjectDir)..\..\repos\LGMP\lgmp\include;$(ProjectDir)..\..\vendor;$(ProjectDir)..\..\common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;d3d12.lib</AdditionalDependencies>
</Link>
<DriverSign>
<FileDigestAlgorithm>SHA1</FileDigestAlgorithm>

View File

@ -48,9 +48,6 @@
<ClInclude Include="CSwapChainProcessor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Direct3DDevice.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CIVSHMEM.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -60,6 +57,27 @@
<ClInclude Include="CPlatformInfo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CD3D12CommandQueue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CInteropResourcePool.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CInteropResource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CD3D12Device.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CD3D11Device.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CFrameBufferResource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CFrameBufferPool.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Device.cpp">
@ -77,9 +95,6 @@
<ClCompile Include="CSwapChainProcessor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Direct3DDevice.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CIVSHMEM.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -89,5 +104,26 @@
<ClCompile Include="CPlatformInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CD3D12CommandQueue.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CInteropResourcePool.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CInteropResource.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CD3D12Device.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CD3D11Device.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CFrameBufferResource.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CFrameBufferPool.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

@ -1 +1 @@
Subproject commit eddecb588839b2b88ac3a77e0a064daa96aab541
Subproject commit f8482c14aae84edf5fc0f3a8c5d3ade0c29df219