diff --git a/idd/LGIdd/Direct3DDevice.cpp b/idd/LGIdd/CD3D11Device.cpp similarity index 64% rename from idd/LGIdd/Direct3DDevice.cpp rename to idd/LGIdd/CD3D11Device.cpp index 2a18b56e..83f35e76 100644 --- a/idd/LGIdd/Direct3DDevice.cpp +++ b/idd/LGIdd/CD3D11Device.cpp @@ -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 device; + ComPtr 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; diff --git a/idd/LGIdd/Direct3DDevice.h b/idd/LGIdd/CD3D11Device.h similarity index 71% rename from idd/LGIdd/Direct3DDevice.h rename to idd/LGIdd/CD3D11Device.h index 1ad002ef..07c3d072 100644 --- a/idd/LGIdd/Direct3DDevice.h +++ b/idd/LGIdd/CD3D11Device.h @@ -26,21 +26,29 @@ #include #include -struct Direct3DDevice +using namespace Microsoft::WRL; + +struct CD3D11Device { - Direct3DDevice(LUID adapterLuid) : +private: + LUID m_adapterLuid; + ComPtr m_factory; + ComPtr m_adapter; + ComPtr m_device; + ComPtr m_context; + +public: + CD3D11Device(LUID adapterLuid) : m_adapterLuid(adapterLuid) {}; - Direct3DDevice() + CD3D11Device() { m_adapterLuid = LUID{}; } HRESULT Init(); - LUID m_adapterLuid; - Microsoft::WRL::ComPtr m_factory; - Microsoft::WRL::ComPtr m_adapter; - Microsoft::WRL::ComPtr m_device; - Microsoft::WRL::ComPtr m_context; + ComPtr GetDevice() { return m_device; } + + ComPtr GetContext() { return m_context; } }; \ No newline at end of file diff --git a/idd/LGIdd/CD3D12CommandQueue.cpp b/idd/LGIdd/CD3D12CommandQueue.cpp new file mode 100644 index 00000000..53346d67 --- /dev/null +++ b/idd/LGIdd/CD3D12CommandQueue.cpp @@ -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; +} + + diff --git a/idd/LGIdd/CD3D12CommandQueue.h b/idd/LGIdd/CD3D12CommandQueue.h new file mode 100644 index 00000000..4d286b95 --- /dev/null +++ b/idd/LGIdd/CD3D12CommandQueue.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include + +using namespace Microsoft::WRL; + +class CD3D12CommandQueue +{ + private: + const WCHAR * m_name = nullptr; + + ComPtr m_queue; + ComPtr m_allocator; + ComPtr m_gfxList; + ComPtr m_cmdList; + ComPtr m_fence; + + Wrappers::HandleT 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 GetCmdQueue() { return m_queue; } + ComPtr GetGfxList() { return m_gfxList; } +}; + diff --git a/idd/LGIdd/CD3D12Device.cpp b/idd/LGIdd/CD3D12Device.cpp new file mode 100644 index 00000000..d98b41a8 --- /dev/null +++ b/idd/LGIdd/CD3D12Device.cpp @@ -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 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; +} diff --git a/idd/LGIdd/CD3D12Device.h b/idd/LGIdd/CD3D12Device.h new file mode 100644 index 00000000..ce8522f8 --- /dev/null +++ b/idd/LGIdd/CD3D12Device.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "CIVSHMEM.h" +#include "CD3D12CommandQueue.h" + +using namespace Microsoft::WRL; + +struct CD3D12Device +{ + private: + LUID m_adapterLuid; + bool m_debug; + bool m_indirectCopy; + + ComPtr m_dxDebug; + ComPtr m_infoQueue; + DWORD m_callbackCookie; + + ComPtr m_factory; + ComPtr m_adapter; + ComPtr m_device; + ComPtr 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 GetDevice() { return m_device; } + ComPtr GetHeap() { return m_ivshmemHeap; } + bool IsIndirectCopy() { return m_indirectCopy; } + + CD3D12CommandQueue& GetCopyQueue() { return m_copyQueue; } + CD3D12CommandQueue& GetComputeQueue() { return m_computeQueue; } +}; \ No newline at end of file diff --git a/idd/LGIdd/CFrameBufferPool.cpp b/idd/LGIdd/CFrameBufferPool.cpp new file mode 100644 index 00000000..48a17417 --- /dev/null +++ b/idd/LGIdd/CFrameBufferPool.cpp @@ -0,0 +1,31 @@ +#include "CFrameBufferPool.h" +#include "CSwapChainProcessor.h" + +#include + +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; +} diff --git a/idd/LGIdd/CFrameBufferPool.h b/idd/LGIdd/CFrameBufferPool.h new file mode 100644 index 00000000..f6a0de4a --- /dev/null +++ b/idd/LGIdd/CFrameBufferPool.h @@ -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); +}; \ No newline at end of file diff --git a/idd/LGIdd/CFrameBufferResource.cpp b/idd/LGIdd/CFrameBufferResource.cpp new file mode 100644 index 00000000..9ab46278 --- /dev/null +++ b/idd/LGIdd/CFrameBufferResource.cpp @@ -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; +} \ No newline at end of file diff --git a/idd/LGIdd/CFrameBufferResource.h b/idd/LGIdd/CFrameBufferResource.h new file mode 100644 index 00000000..22cbe9fd --- /dev/null +++ b/idd/LGIdd/CFrameBufferResource.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include +#include +#include + +class CSwapChainProcessor; + +using namespace Microsoft::WRL; + +class CFrameBufferResource +{ + private: + bool m_valid; + uint8_t * m_base; + size_t m_size; + ComPtr 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 Get() { return m_res; } +}; diff --git a/idd/LGIdd/CIVSHMEM.cpp b/idd/LGIdd/CIVSHMEM.cpp index a16c24a8..34983cb5 100644 --- a/idd/LGIdd/CIVSHMEM.cpp +++ b/idd/LGIdd/CIVSHMEM.cpp @@ -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) diff --git a/idd/LGIdd/CIndirectDeviceContext.cpp b/idd/LGIdd/CIndirectDeviceContext.cpp index 89878fec..f54ed95a 100644 --- a/idd/LGIdd/CIndirectDeviceContext.cpp +++ b/idd/LGIdd/CIndirectDeviceContext.cpp @@ -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; diff --git a/idd/LGIdd/CIndirectDeviceContext.h b/idd/LGIdd/CIndirectDeviceContext.h index d05fb123..0ec38a9c 100644 --- a/idd/LGIdd/CIndirectDeviceContext.h +++ b/idd/LGIdd/CIndirectDeviceContext.h @@ -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 diff --git a/idd/LGIdd/CIndirectMonitorContext.cpp b/idd/LGIdd/CIndirectMonitorContext.cpp index 6ac50f08..9043ad10 100644 --- a/idd/LGIdd/CIndirectMonitorContext.cpp +++ b/idd/LGIdd/CIndirectMonitorContext.cpp @@ -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(renderAdapter); - if (FAILED(device->Init())) + m_dx11Device = std::make_shared(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(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) diff --git a/idd/LGIdd/CIndirectMonitorContext.h b/idd/LGIdd/CIndirectMonitorContext.h index f5ec5441..0681cb9e 100644 --- a/idd/LGIdd/CIndirectMonitorContext.h +++ b/idd/LGIdd/CIndirectMonitorContext.h @@ -34,6 +34,10 @@ class CIndirectMonitorContext { private: IDDCX_MONITOR m_monitor; + + std::shared_ptr m_dx11Device; + std::shared_ptr m_dx12Device; + CIndirectDeviceContext * m_devContext; std::unique_ptr m_swapChain; diff --git a/idd/LGIdd/CInteropResource.cpp b/idd/LGIdd/CInteropResource.cpp new file mode 100644 index 00000000..a17d798c --- /dev/null +++ b/idd/LGIdd/CInteropResource.cpp @@ -0,0 +1,127 @@ +#include "CInteropResource.h" + +#include "Debug.h" + +bool CInteropResource::Init(std::shared_ptr dx11Device, std::shared_ptr dx12Device, ComPtr srcTex) +{ + HRESULT hr; + + D3D11_TEXTURE2D_DESC srcDesc; + srcTex->GetDesc(&srcDesc); + + ComPtr rSrcTex; + hr = srcTex.As(&rSrcTex); + if (FAILED(hr)) + { + DBGPRINT_HR(hr, "Failed to obtain the IDXGIResource1 interface"); + return false; + } + + HANDLE h; + Wrappers::HandleT 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 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 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 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& 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; +} \ No newline at end of file diff --git a/idd/LGIdd/CInteropResource.h b/idd/LGIdd/CInteropResource.h new file mode 100644 index 00000000..7c986202 --- /dev/null +++ b/idd/LGIdd/CInteropResource.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include + +#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 m_dx11Device; + std::shared_ptr 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 m_d12Res; + D3D11_TEXTURE2D_DESC m_format; + ComPtr m_d11Fence; + ComPtr m_d12Fence; + UINT64 m_fenceValue; + bool m_ready; + + RECT m_dirtyRects[LG_MAX_DIRTY_RECTS]; + unsigned m_nbDirtyRects; + + public: + bool Init(std::shared_ptr dx11Device, std::shared_ptr dx12Device, ComPtr srcTex); + void Reset(); + + bool IsReady() { return m_ready; } + bool Compare(const ComPtr& srcTex); + void Signal(); + void Sync(CD3D12CommandQueue& queue); + void SetFullDamage(); + + const ComPtr& GetRes() { return m_d12Res; } + const D3D11_TEXTURE2D_DESC& GetFormat() { return m_format; } +}; \ No newline at end of file diff --git a/idd/LGIdd/CInteropResourcePool.cpp b/idd/LGIdd/CInteropResourcePool.cpp new file mode 100644 index 00000000..de8a2a33 --- /dev/null +++ b/idd/LGIdd/CInteropResourcePool.cpp @@ -0,0 +1,47 @@ +#include "CInteropResourcePool.h" +#include "Debug.h" + +void CInteropResourcePool::Init(std::shared_ptr dx11Device, std::shared_ptr 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 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; +} \ No newline at end of file diff --git a/idd/LGIdd/CInteropResourcePool.h b/idd/LGIdd/CInteropResourcePool.h new file mode 100644 index 00000000..c3f1ccb2 --- /dev/null +++ b/idd/LGIdd/CInteropResourcePool.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include +#include +#include "CInteropResource.h" + +using namespace Microsoft::WRL; + +#define POOL_SIZE 10 + +class CInteropResourcePool +{ + private: + CInteropResource m_pool[POOL_SIZE]; + + std::shared_ptr m_dx11Device; + std::shared_ptr m_dx12Device; + + public: + void Init(std::shared_ptr dx11Device, std::shared_ptr dx12Device); + void Reset(); + + CInteropResource* Get(ComPtr srcTex); +}; \ No newline at end of file diff --git a/idd/LGIdd/CSwapChainProcessor.cpp b/idd/LGIdd/CSwapChainProcessor.cpp index 20b4336e..eb0b66d4 100644 --- a/idd/LGIdd/CSwapChainProcessor.cpp +++ b/idd/LGIdd/CSwapChainProcessor.cpp @@ -35,15 +35,18 @@ #define UNLOCK_ST(st) UNLOCK((st).lock); CSwapChainProcessor::CSwapChainProcessor(CIndirectDeviceContext* devContext, IDDCX_SWAPCHAIN hSwapChain, - std::shared_ptr device, HANDLE newFrameEvent) : + std::shared_ptr dx11Device, std::shared_ptr 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 dxgiDevice; - HRESULT hr = m_device->m_device.As(&dxgiDevice); + ComPtr 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 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 acquiredBuffer) { - Microsoft::WRL::ComPtr texture; - if (FAILED(acquiredBuffer->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&texture))) + ComPtr 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(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); +*/ } \ No newline at end of file diff --git a/idd/LGIdd/CSwapChainProcessor.h b/idd/LGIdd/CSwapChainProcessor.h index 9748d0da..8ac17bdf 100644 --- a/idd/LGIdd/CSwapChainProcessor.h +++ b/idd/LGIdd/CSwapChainProcessor.h @@ -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 #include @@ -37,45 +40,29 @@ class CSwapChainProcessor private: CIndirectDeviceContext * m_devContext; IDDCX_SWAPCHAIN m_hSwapChain; - std::shared_ptr m_device; + std::shared_ptr m_dx11Device; + std::shared_ptr m_dx12Device; HANDLE m_newFrameEvent; + CInteropResourcePool m_resPool; + CFrameBufferPool m_fbPool; + Wrappers::HandleT 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 acquiredBuffer); - void FrameThread(); - - struct StagingTexture - { - volatile LONG lock = 0; - - int width = 0; - int height = 0; - DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; - Microsoft::WRL::ComPtr 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 device, HANDLE newFrameEvent); + std::shared_ptr dx11Device, std::shared_ptr dx12Device, HANDLE newFrameEvent); ~CSwapChainProcessor(); + CIndirectDeviceContext * GetDevice() { return m_devContext; } + std::shared_ptr GetD3D12Device() { return m_dx12Device; } + void ResendLastFrame(); }; \ No newline at end of file diff --git a/idd/LGIdd/Debug.cpp b/idd/LGIdd/Debug.cpp index 9ef3fc8a..3b399947 100644 --- a/idd/LGIdd/Debug.cpp +++ b/idd/LGIdd/Debug.cpp @@ -22,18 +22,21 @@ #include #include +#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); } \ No newline at end of file diff --git a/idd/LGIdd/Debug.h b/idd/LGIdd/Debug.h index 3841c6f9..56d8a919 100644 --- a/idd/LGIdd/Debug.h +++ b/idd/LGIdd/Debug.h @@ -25,4 +25,8 @@ VOID _DBGPRINT(PCSTR kszFunction, INT iLineNumber, LPCSTR kszDebugFormatString, ...); #define DBGPRINT(kszDebugFormatString, ...) \ - _DBGPRINT(__FUNCTION__, __LINE__, kszDebugFormatString, __VA_ARGS__) \ No newline at end of file + _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__) diff --git a/idd/LGIdd/Device.cpp b/idd/LGIdd/Device.cpp index 5cf0099d..2f562663 100644 --- a/idd/LGIdd/Device.cpp +++ b/idd/LGIdd/Device.cpp @@ -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; } diff --git a/idd/LGIdd/Driver.cpp b/idd/LGIdd/Driver.cpp index 60cbd5b7..bcdc8188 100644 --- a/idd/LGIdd/Driver.cpp +++ b/idd/LGIdd/Driver.cpp @@ -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) diff --git a/idd/LGIdd/LGIdd.vcxproj b/idd/LGIdd/LGIdd.vcxproj index 39488c11..9862731f 100644 --- a/idd/LGIdd/LGIdd.vcxproj +++ b/idd/LGIdd/LGIdd.vcxproj @@ -38,24 +38,36 @@ + + + + + + - + + + + + + + - + @@ -257,7 +269,7 @@ $(ProjectDir)..\..\repos\LGMP\lgmp\include;$(ProjectDir)..\..\vendor;$(ProjectDir)..\..\common\include;%(AdditionalIncludeDirectories) - %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib + %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;d3d12.lib SHA1 @@ -272,7 +284,7 @@ $(ProjectDir)..\..\repos\LGMP\lgmp\include;$(ProjectDir)..\..\vendor;$(ProjectDir)..\..\common\include;%(AdditionalIncludeDirectories) - %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib + %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;d3d12.lib SHA1 diff --git a/idd/LGIdd/LGIdd.vcxproj.filters b/idd/LGIdd/LGIdd.vcxproj.filters index e32af2b7..37730af6 100644 --- a/idd/LGIdd/LGIdd.vcxproj.filters +++ b/idd/LGIdd/LGIdd.vcxproj.filters @@ -48,9 +48,6 @@ Header Files - - Header Files - Header Files @@ -60,6 +57,27 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + @@ -77,9 +95,6 @@ Source Files - - Source Files - Source Files @@ -89,5 +104,26 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + \ No newline at end of file diff --git a/repos/LGMP b/repos/LGMP index eddecb58..f8482c14 160000 --- a/repos/LGMP +++ b/repos/LGMP @@ -1 +1 @@ -Subproject commit eddecb588839b2b88ac3a77e0a064daa96aab541 +Subproject commit f8482c14aae84edf5fc0f3a8c5d3ade0c29df219