mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 08:41:31 +00:00
Move cadence-aware hardware capture and immediate software capture behind a common frame processor interface. Keep shared damage tracking and frame-buffer ownership in the base processor, and move stateless format, resource, and rectangle helpers into CFrameProcessorUtil. Decouple frame-buffer resources from CSwapChainProcessor by passing the device dependencies they use directly.
229 lines
6.8 KiB
C++
229 lines
6.8 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 "CFrameBufferResource.h"
|
|
#include "CFrameProcessorUtil.h"
|
|
#include "CD3D12Device.h"
|
|
#include "CIndirectDeviceContext.h"
|
|
#include "CDebug.h"
|
|
|
|
#include <cstring>
|
|
|
|
bool CFrameBufferResource::Init(CIndirectDeviceContext * device,
|
|
CD3D12Device * dx12, unsigned frameIndex, uint8_t * base, size_t size,
|
|
const D3D12_RESOURCE_DESC * textureDesc)
|
|
{
|
|
m_frameIndex = frameIndex;
|
|
|
|
if (size > device->GetMaxFrameSize())
|
|
{
|
|
DEBUG_ERROR("Frame size of %llu is too large to fit in shared ram",
|
|
(unsigned long long)size);
|
|
return false;
|
|
}
|
|
|
|
const bool indirect = dx12->IsIndirectCopy();
|
|
const ResourceType type = textureDesc ?
|
|
RESOURCE_TEXTURE : RESOURCE_BUFFER;
|
|
|
|
D3D12_RESOURCE_DESC desc = {};
|
|
if (textureDesc)
|
|
{
|
|
if (indirect || !dx12->CanUseIVSHMEMTexture())
|
|
return false;
|
|
desc = *textureDesc;
|
|
if (desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D ||
|
|
!desc.Width ||
|
|
!desc.Height ||
|
|
desc.DepthOrArraySize != 1 ||
|
|
desc.MipLevels != 1 ||
|
|
desc.SampleDesc.Count != 1 ||
|
|
desc.SampleDesc.Quality ||
|
|
desc.Format == DXGI_FORMAT_UNKNOWN ||
|
|
desc.Layout != D3D12_TEXTURE_LAYOUT_ROW_MAJOR ||
|
|
desc.Flags != D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER)
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
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;
|
|
if (!indirect)
|
|
{
|
|
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER;
|
|
}
|
|
}
|
|
|
|
// Nothing to do if the resource already represents this allocation.
|
|
if (m_base == base && m_type == type &&
|
|
((type == RESOURCE_BUFFER && m_size >= size) ||
|
|
(type == RESOURCE_TEXTURE &&
|
|
CFrameProcessorUtil::ResourceDescMatches(m_desc, desc))))
|
|
{
|
|
m_frameSize = size;
|
|
return true;
|
|
}
|
|
|
|
Reset();
|
|
|
|
HRESULT hr;
|
|
const WCHAR * resName;
|
|
UINT64 allocationSize = size;
|
|
|
|
if (indirect)
|
|
{
|
|
DEBUG_TRACE("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 = dx12->GetDevice()->CreateCommittedResource(
|
|
&heapProps,
|
|
D3D12_HEAP_FLAG_NONE,
|
|
&desc,
|
|
D3D12_RESOURCE_STATE_COPY_DEST,
|
|
NULL,
|
|
IID_PPV_ARGS(&m_res)
|
|
);
|
|
resName = L"STAGING";
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
D3D12_RANGE range = {0, 0};
|
|
hr = m_res->Map(0, &range, &m_map);
|
|
if (FAILED(hr))
|
|
{
|
|
DEBUG_ERROR_HR(hr, "Failed to map the resource");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const UINT64 heapOffset =
|
|
(uintptr_t)base -
|
|
(uintptr_t)device->GetIVSHMEM().GetMem();
|
|
const D3D12_RESOURCE_ALLOCATION_INFO allocation =
|
|
dx12->GetDevice()->GetResourceAllocationInfo(0, 1, &desc);
|
|
allocationSize = allocation.SizeInBytes;
|
|
const D3D12_HEAP_DESC heapDesc = dx12->GetHeap()->GetDesc();
|
|
if (!allocation.Alignment ||
|
|
heapOffset % allocation.Alignment ||
|
|
allocation.SizeInBytes > device->GetMaxFrameSize() ||
|
|
heapOffset > heapDesc.SizeInBytes ||
|
|
allocation.SizeInBytes > heapDesc.SizeInBytes - heapOffset)
|
|
{
|
|
DEBUG_ERROR("IVSHMEM resource does not fit its framebuffer allocation");
|
|
return false;
|
|
}
|
|
|
|
if (type == RESOURCE_TEXTURE)
|
|
{
|
|
D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {};
|
|
support.Format = desc.Format;
|
|
hr = dx12->GetDevice()->CheckFeatureSupport(
|
|
D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support));
|
|
if (FAILED(hr) ||
|
|
!(support.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D))
|
|
{
|
|
DEBUG_ERROR("IVSHMEM texture format is unsupported");
|
|
return false;
|
|
}
|
|
DEBUG_TRACE("Creating IVSHMEM texture for %p", base);
|
|
resName = L"IVSHMEM Texture";
|
|
}
|
|
else
|
|
{
|
|
DEBUG_TRACE("Creating IVSHMEM buffer for %p", base);
|
|
resName = L"IVSHMEM";
|
|
}
|
|
|
|
hr = dx12->GetDevice()->CreatePlacedResource(
|
|
dx12->GetHeap().Get(),
|
|
heapOffset,
|
|
&desc,
|
|
D3D12_RESOURCE_STATE_COMMON,
|
|
NULL,
|
|
IID_PPV_ARGS(&m_res)
|
|
);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DEBUG_ERROR_HR(hr, "Failed to create the FrameBuffer ID3D12Resource");
|
|
return false;
|
|
}
|
|
|
|
m_res->SetName(resName);
|
|
|
|
m_base = base;
|
|
m_size = type == RESOURCE_TEXTURE ?
|
|
(size_t)allocationSize : size;
|
|
m_frameSize = size;
|
|
m_type = type;
|
|
m_desc = desc;
|
|
return true;
|
|
}
|
|
|
|
void CFrameBufferResource::Reset()
|
|
{
|
|
if (m_map)
|
|
{
|
|
m_res->Unmap(0, NULL);
|
|
m_map = NULL;
|
|
}
|
|
|
|
m_base = nullptr;
|
|
m_size = 0;
|
|
m_frameSize = 0;
|
|
m_type = RESOURCE_NONE;
|
|
m_desc = {};
|
|
m_fullCopy = false;
|
|
m_nbCopyDirtyRects = 0;
|
|
m_copyPitch = 0;
|
|
m_copyBytesPerPixel = 0;
|
|
m_res.Reset();
|
|
}
|
|
|
|
void CFrameBufferResource::SetCopyDamage(const RECT dirtyRects[],
|
|
unsigned nbDirtyRects, bool fullCopy, unsigned pitch,
|
|
unsigned bytesPerPixel)
|
|
{
|
|
m_fullCopy = fullCopy;
|
|
m_nbCopyDirtyRects = fullCopy ? 0 : nbDirtyRects;
|
|
m_copyPitch = pitch;
|
|
m_copyBytesPerPixel = bytesPerPixel;
|
|
if (m_nbCopyDirtyRects)
|
|
memcpy(m_copyDirtyRects, dirtyRects,
|
|
m_nbCopyDirtyRects * sizeof(*m_copyDirtyRects));
|
|
}
|