Files
LookingGlass/idd/LGIdd/d3d/CD3D12Device.cpp
Geoffrey McRae 6725133375 [idd] transport: abstract LGMP implementation
Introduce transport, frame, and control interfaces with an LGMP factory
backend.

Move LGMP and IVSHMEM implementation details under transport/lgmp and
expose direct frame-buffer memory through a neutral capability.
2026-08-07 17:53:00 +10:00

236 lines
6.4 KiB
C++

/**
* Looking Glass
* Copyright © 2017-2026 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "d3d/CD3D12Device.h"
#include "CDebug.h"
bool CD3D12Device::s_directHeapFailed = false;
CD3D12Device::CD3D12Device(LUID adapterLuid) :
m_adapterLuid(adapterLuid),
m_debug(false)
{
if (m_debug)
{
HRESULT hr = D3D12GetDebugInterface(IID_PPV_ARGS(&m_dxDebug));
if (FAILED(hr))
{
DEBUG_ERROR_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;
DEBUG_INFO("category:%d severity:%d id:%d desc:%s",
category,
severity,
id,
description);
}
CD3D12Device::InitResult CD3D12Device::Init(
const DirectFrameBufferMemory& directMemory,
UINT64& alignSize, bool enableCompute)
{
HRESULT hr;
m_computeEnabled = enableCompute;
m_indirectCopy = !directMemory || s_directHeapFailed;
hr = CreateDXGIFactory2(m_debug ? DXGI_CREATE_FACTORY_DEBUG : 0, IID_PPV_ARGS(&m_factory));
if (FAILED(hr))
{
DEBUG_ERROR_HR(hr, "Failed to create the DXGI factory");
return InitResult::FAILURE;
}
hr = m_factory->EnumAdapterByLuid(m_adapterLuid, IID_PPV_ARGS(&m_adapter));
if (FAILED(hr))
{
DEBUG_ERROR_HR(hr, "Failed to enumerate the adapter");
return InitResult::FAILURE;
}
hr = D3D12CreateDevice(m_adapter.Get(), D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(&m_device));
if (FAILED(hr))
{
DEBUG_ERROR_HR(hr, "Failed to create the DirectX12 device");
return InitResult::FAILURE;
}
if (m_debug)
{
hr = m_device.As(&m_infoQueue);
if (FAILED(hr))
{
DEBUG_WARN_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(
directMemory.address, IID_PPV_ARGS(&m_transportHeap));
if (FAILED(hr))
{
DEBUG_ERROR_HR(hr,
"Failed to open transport memory as a D3D12 heap");
s_directHeapFailed = true;
return InitResult::RETRY;
}
m_transportHeap->SetName(L"Transport Memory");
D3D12_HEAP_DESC heapDesc = m_transportHeap->GetDesc();
alignSize = heapDesc.Alignment;
m_directTextureSupported =
(heapDesc.Flags & D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER) &&
!(heapDesc.Flags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES);
// test that the heap is usable
if (!HeapTest())
{
DEBUG_WARN("Unable to create resources in transport memory, "
"falling back to indirect copy");
// failure often results in the device being removed and we need to completely reinit when this occurs
s_directHeapFailed = true;
return InitResult::RETRY;
}
DEBUG_INFO("Using transport memory as a D3D12 heap");
if (!m_directTextureSupported)
DEBUG_WARN("Transport memory does not support placed textures");
}
if (!m_copyQueue.Init(m_device.Get(), D3D12_COMMAND_LIST_TYPE_COPY,
L"Copy", m_indirectCopy ? CD3D12CommandSlot::NORMAL :
CD3D12CommandSlot::FAST, 2, true))
return InitResult::FAILURE;
if (m_computeEnabled &&
!m_computeQueue.Init(m_device.Get(), D3D12_COMMAND_LIST_TYPE_COMPUTE,
L"Compute", CD3D12CommandSlot::FAST, 2))
return InitResult::FAILURE;
DEBUG_INFO("Created CD3D12Device");
return InitResult::SUCCESS;
}
void CD3D12Device::DeInit()
{
if (m_debug && m_infoQueue)
m_infoQueue->UnregisterMessageCallback(m_callbackCookie);
m_infoQueue.Reset();
}
void CD3D12Device::WaitForIdle()
{
m_copyQueue.WaitForIdle();
if (m_computeEnabled)
m_computeQueue.WaitForIdle();
}
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_transportHeap.Get(),
0,
&desc,
D3D12_RESOURCE_STATE_COPY_DEST,
NULL,
IID_PPV_ARGS(&resource));
if (FAILED(hr))
{
DEBUG_ERROR_HR(hr,
"Failed to create the transport-memory 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)
{
DEBUG_ERROR_HR(hr, "Device Removed");
return false;
}
return true;
}
CD3D12CommandSlot * CD3D12Device::GetCopySlot(unsigned frameIndex)
{
return m_copyQueue.Acquire(frameIndex);
}
CD3D12CommandSlot * CD3D12Device::GetCopySlot()
{
return m_copyQueue.Acquire();
}
CD3D12CommandSlot * CD3D12Device::GetComputeSlot(unsigned frameIndex)
{
if (!m_computeEnabled)
{
DEBUG_ERROR("Compute queue requested while compute processing is disabled");
return nullptr;
}
return m_computeQueue.Acquire(frameIndex);
}