mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 00:31:31 +00:00
Use an explicit placed buffer for software frame copies so the D3D copy uses the same row pitch published through KVMFR. GetCopyableFootprints describes buffer copies and cannot be used to infer the physical layout of a placed row-major texture. This caused padded resolutions to use the wrong row starts in every consumer. Keep the copy direct to IVSHMEM without a staging or CPU copy.
231 lines
6.2 KiB
C++
231 lines
6.2 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;
|
|
|
|
// 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_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);
|
|
}
|