mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 07:01:30 +00:00
[idd] capture: build frame processing graph
This commit is contained in:
@@ -43,6 +43,7 @@
|
|||||||
<ClCompile Include="display\CMonitorContext.cpp" />
|
<ClCompile Include="display\CMonitorContext.cpp" />
|
||||||
<ClCompile Include="capture\CFrameBufferPool.cpp" />
|
<ClCompile Include="capture\CFrameBufferPool.cpp" />
|
||||||
<ClCompile Include="capture\CFrameBufferResource.cpp" />
|
<ClCompile Include="capture\CFrameBufferResource.cpp" />
|
||||||
|
<ClCompile Include="capture\CFrameGraph.cpp" />
|
||||||
<ClCompile Include="capture\CFrameProcessor.cpp" />
|
<ClCompile Include="capture\CFrameProcessor.cpp" />
|
||||||
<ClCompile Include="capture\CFrameProcessorUtil.cpp" />
|
<ClCompile Include="capture\CFrameProcessorUtil.cpp" />
|
||||||
<ClCompile Include="capture\CFrameScheduler.cpp" />
|
<ClCompile Include="capture\CFrameScheduler.cpp" />
|
||||||
@@ -95,6 +96,7 @@
|
|||||||
<ClInclude Include="display\CMonitorContext.h" />
|
<ClInclude Include="display\CMonitorContext.h" />
|
||||||
<ClInclude Include="capture\CFrameBufferPool.h" />
|
<ClInclude Include="capture\CFrameBufferPool.h" />
|
||||||
<ClInclude Include="capture\CFrameBufferResource.h" />
|
<ClInclude Include="capture\CFrameBufferResource.h" />
|
||||||
|
<ClInclude Include="capture\CFrameGraph.h" />
|
||||||
<ClInclude Include="capture\CFrameProcessor.h" />
|
<ClInclude Include="capture\CFrameProcessor.h" />
|
||||||
<ClInclude Include="capture\CFrameProcessorUtil.h" />
|
<ClInclude Include="capture\CFrameProcessorUtil.h" />
|
||||||
<ClInclude Include="capture\CFrameScheduler.h" />
|
<ClInclude Include="capture\CFrameScheduler.h" />
|
||||||
|
|||||||
@@ -97,6 +97,9 @@
|
|||||||
<ClInclude Include="capture\CFrameBufferResource.h">
|
<ClInclude Include="capture\CFrameBufferResource.h">
|
||||||
<Filter>Capture</Filter>
|
<Filter>Capture</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="capture\CFrameGraph.h">
|
||||||
|
<Filter>Capture</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="capture\CFrameProcessor.h">
|
<ClInclude Include="capture\CFrameProcessor.h">
|
||||||
<Filter>Capture</Filter>
|
<Filter>Capture</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -273,6 +276,9 @@
|
|||||||
<ClCompile Include="capture\CFrameBufferResource.cpp">
|
<ClCompile Include="capture\CFrameBufferResource.cpp">
|
||||||
<Filter>Capture</Filter>
|
<Filter>Capture</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="capture\CFrameGraph.cpp">
|
||||||
|
<Filter>Capture</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="capture\CFrameProcessor.cpp">
|
<ClCompile Include="capture\CFrameProcessor.cpp">
|
||||||
<Filter>Capture</Filter>
|
<Filter>Capture</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
286
idd/LGIdd/capture/CFrameGraph.cpp
Normal file
286
idd/LGIdd/capture/CFrameGraph.cpp
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
/**
|
||||||
|
* 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 "capture/CFrameGraph.h"
|
||||||
|
|
||||||
|
bool Frame::Same(const GraphCfg& left, const GraphCfg& right)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
left.mode == right.mode &&
|
||||||
|
Frame::Same(left.adapter, right.adapter) &&
|
||||||
|
left.srcWidth == right.srcWidth &&
|
||||||
|
left.srcHeight == right.srcHeight &&
|
||||||
|
Frame::Same(left.src, right.src) &&
|
||||||
|
left.width == right.width &&
|
||||||
|
left.height == right.height &&
|
||||||
|
Frame::Same(left.checkpoint, right.checkpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Frame::Valid(FrameDamage damage, const RECT * rects, unsigned count,
|
||||||
|
unsigned width, unsigned height)
|
||||||
|
{
|
||||||
|
switch (damage)
|
||||||
|
{
|
||||||
|
case FrameDamage::NONE:
|
||||||
|
case FrameDamage::FULL:
|
||||||
|
return count == 0;
|
||||||
|
|
||||||
|
case FrameDamage::RECTS:
|
||||||
|
if (!rects || !count || count > FRAME_DAMAGE_MAX)
|
||||||
|
return false;
|
||||||
|
for (unsigned i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
const RECT& rect = rects[i];
|
||||||
|
if (rect.left < 0 ||
|
||||||
|
rect.top < 0 ||
|
||||||
|
rect.left >= rect.right ||
|
||||||
|
rect.top >= rect.bottom ||
|
||||||
|
static_cast<unsigned long>(rect.right) > width ||
|
||||||
|
static_cast<unsigned long>(rect.bottom) > height)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFrameGraph::Reset()
|
||||||
|
{
|
||||||
|
m_cfg = GraphCfg {};
|
||||||
|
m_nodeCount = 0;
|
||||||
|
m_leafCount = 0;
|
||||||
|
m_begun = false;
|
||||||
|
m_sealed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFrameGraph::Begin(const GraphCfg& cfg)
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
if (!cfg.srcWidth || !cfg.srcHeight || !cfg.width || !cfg.height ||
|
||||||
|
!Frame::Valid(cfg.mode) ||
|
||||||
|
cfg.src.storage != FrameStorage::D3D12_TEXTURE ||
|
||||||
|
cfg.checkpoint.storage != FrameStorage::D3D12_TEXTURE ||
|
||||||
|
!Frame::Valid(cfg.src) || !Frame::Valid(cfg.checkpoint) ||
|
||||||
|
!Frame::Can(cfg.src.signal, cfg.checkpoint.signal))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_cfg = cfg;
|
||||||
|
GraphNode& source = m_nodes[m_nodeCount++];
|
||||||
|
source = GraphNode {};
|
||||||
|
source.op = FrameOp::SRC;
|
||||||
|
source.parent = FRAME_GRAPH_ROOT;
|
||||||
|
source.width = cfg.srcWidth;
|
||||||
|
source.height = cfg.srcHeight;
|
||||||
|
source.profile = cfg.src;
|
||||||
|
m_begun = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFrameGraph::Can(const FrameCfg& cfg) const
|
||||||
|
{
|
||||||
|
if (!m_begun || m_sealed || !cfg.width || !cfg.height ||
|
||||||
|
cfg.width != m_cfg.width || cfg.height != m_cfg.height ||
|
||||||
|
cfg.mode != m_cfg.mode ||
|
||||||
|
!Frame::Same(cfg.adapter, m_cfg.adapter) ||
|
||||||
|
!Frame::Valid(cfg.profile))
|
||||||
|
return false;
|
||||||
|
return Frame::Can(m_cfg.src.signal, cfg.profile.signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned CFrameGraph::Find(FrameOp op, unsigned parent,
|
||||||
|
unsigned width, unsigned height,
|
||||||
|
const FrameProfile& profile) const
|
||||||
|
{
|
||||||
|
for (unsigned i = 1; i < m_nodeCount; ++i)
|
||||||
|
if (m_nodes[i].op == op && m_nodes[i].parent == parent &&
|
||||||
|
m_nodes[i].width == width && m_nodes[i].height == height &&
|
||||||
|
Frame::Same(m_nodes[i].profile, profile))
|
||||||
|
return i;
|
||||||
|
return FRAME_GRAPH_ROOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned CFrameGraph::AddNode(FrameOp op, unsigned parent,
|
||||||
|
unsigned width, unsigned height,
|
||||||
|
const FrameProfile& profile)
|
||||||
|
{
|
||||||
|
const unsigned found = Find(op, parent, width, height, profile);
|
||||||
|
if (found != FRAME_GRAPH_ROOT)
|
||||||
|
return found;
|
||||||
|
if (m_nodeCount == FRAME_GRAPH_MAX_NODES)
|
||||||
|
return FRAME_GRAPH_ROOT;
|
||||||
|
|
||||||
|
const unsigned index = m_nodeCount++;
|
||||||
|
GraphNode& node = m_nodes[index];
|
||||||
|
node = GraphNode {};
|
||||||
|
node.op = op;
|
||||||
|
node.parent = parent;
|
||||||
|
node.width = width;
|
||||||
|
node.height = height;
|
||||||
|
node.profile = profile;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned CFrameGraph::Checkpoint(const FrameProfile& requested)
|
||||||
|
{
|
||||||
|
const FrameProfile profile =
|
||||||
|
Frame::Store(requested, FrameStorage::D3D12_TEXTURE);
|
||||||
|
unsigned parent = 0;
|
||||||
|
FrameOp op;
|
||||||
|
switch (profile.signal)
|
||||||
|
{
|
||||||
|
case FrameSignal::SRGB:
|
||||||
|
op = FrameOp::SDR;
|
||||||
|
parent = AddNode(FrameOp::SDR, 0, m_cfg.width, m_cfg.height,
|
||||||
|
m_cfg.checkpoint);
|
||||||
|
if (parent == FRAME_GRAPH_ROOT)
|
||||||
|
return FRAME_GRAPH_ROOT;
|
||||||
|
if (Frame::Same(profile, m_cfg.checkpoint))
|
||||||
|
return parent;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FrameSignal::SCRGB_LINEAR:
|
||||||
|
{
|
||||||
|
op = FrameOp::SCRGB;
|
||||||
|
FrameProfile scRGB;
|
||||||
|
scRGB.storage = FrameStorage::D3D12_TEXTURE;
|
||||||
|
scRGB.pixel = FramePixel::RGBA16F;
|
||||||
|
scRGB.signal = FrameSignal::SCRGB_LINEAR;
|
||||||
|
return AddNode(
|
||||||
|
op, 0, m_cfg.width, m_cfg.height, scRGB);
|
||||||
|
}
|
||||||
|
|
||||||
|
case FrameSignal::PQ_BT2020:
|
||||||
|
op = FrameOp::HDR10;
|
||||||
|
if (m_cfg.src.signal == FrameSignal::SCRGB_LINEAR)
|
||||||
|
{
|
||||||
|
FrameProfile scRGB;
|
||||||
|
scRGB.storage = FrameStorage::D3D12_TEXTURE;
|
||||||
|
scRGB.pixel = FramePixel::RGBA16F;
|
||||||
|
scRGB.signal = FrameSignal::SCRGB_LINEAR;
|
||||||
|
parent = AddNode(
|
||||||
|
FrameOp::SCRGB, 0, m_cfg.width, m_cfg.height, scRGB);
|
||||||
|
if (parent == FRAME_GRAPH_ROOT)
|
||||||
|
return FRAME_GRAPH_ROOT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent = AddNode(FrameOp::HDR10, 0,
|
||||||
|
m_cfg.width, m_cfg.height, m_cfg.checkpoint);
|
||||||
|
if (parent == FRAME_GRAPH_ROOT)
|
||||||
|
return FRAME_GRAPH_ROOT;
|
||||||
|
if (Frame::Same(profile, m_cfg.checkpoint))
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return FRAME_GRAPH_ROOT;
|
||||||
|
}
|
||||||
|
return AddNode(
|
||||||
|
op, parent, m_cfg.width, m_cfg.height, profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFrameGraph::Add(BackendId id, uint32_t epoch, bool required,
|
||||||
|
bool primary, const FrameCfg& cfg)
|
||||||
|
{
|
||||||
|
if (!id || !epoch || !Can(cfg) ||
|
||||||
|
m_leafCount == TRANSPORT_MAX_INSTANCES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < m_leafCount; ++i)
|
||||||
|
if (m_leaves[i].id == id && m_leaves[i].epoch == epoch)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const CFrameGraph before = *this;
|
||||||
|
const unsigned node = Checkpoint(cfg.profile);
|
||||||
|
if (node == FRAME_GRAPH_ROOT)
|
||||||
|
{
|
||||||
|
*this = before;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GraphLeaf& leaf = m_leaves[m_leafCount++];
|
||||||
|
leaf = GraphLeaf {};
|
||||||
|
leaf.id = id;
|
||||||
|
leaf.epoch = epoch;
|
||||||
|
leaf.node = node;
|
||||||
|
leaf.required = required;
|
||||||
|
leaf.primary = primary;
|
||||||
|
leaf.cfg = cfg;
|
||||||
|
|
||||||
|
for (unsigned current = node;
|
||||||
|
current != FRAME_GRAPH_ROOT; current = m_nodes[current].parent)
|
||||||
|
++m_nodes[current].refs;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFrameGraph::Seal()
|
||||||
|
{
|
||||||
|
if (!m_begun || m_sealed || !m_leafCount || !m_nodeCount ||
|
||||||
|
!m_nodes[0].refs)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < m_leafCount; ++i)
|
||||||
|
if (!m_leaves[i].id || !m_leaves[i].epoch ||
|
||||||
|
!m_leaves[i].node || m_leaves[i].node >= m_nodeCount)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_sealed = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFrameGraph::Same(const GraphCfg& cfg) const
|
||||||
|
{
|
||||||
|
return m_sealed && Frame::Same(m_cfg, cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFrameGraph::Desc(unsigned leaf, const FrameDesc& frame,
|
||||||
|
LeafDesc& desc) const
|
||||||
|
{
|
||||||
|
if (!m_sealed || leaf >= m_leafCount || !frame.serial ||
|
||||||
|
frame.format.width != m_cfg.srcWidth ||
|
||||||
|
frame.format.height != m_cfg.srcHeight ||
|
||||||
|
!Frame::Valid(frame.damage, frame.rects, frame.count,
|
||||||
|
m_cfg.srcWidth, m_cfg.srcHeight))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const GraphLeaf& route = m_leaves[leaf];
|
||||||
|
const GraphNode& node = m_nodes[route.node];
|
||||||
|
desc.id = route.id;
|
||||||
|
desc.epoch = route.epoch;
|
||||||
|
desc.node = route.node;
|
||||||
|
desc.profile = route.cfg.profile;
|
||||||
|
desc.frame = frame;
|
||||||
|
|
||||||
|
D12FrameFormat& format = desc.frame.format;
|
||||||
|
return D12::Set(format, node.profile, node.width, node.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
const GraphNode * CFrameGraph::Nodes(unsigned& count) const
|
||||||
|
{
|
||||||
|
count = m_sealed ? m_nodeCount : 0;
|
||||||
|
return count ? m_nodes : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GraphLeaf * CFrameGraph::Leaves(unsigned& count) const
|
||||||
|
{
|
||||||
|
count = m_sealed ? m_leafCount : 0;
|
||||||
|
return count ? m_leaves : nullptr;
|
||||||
|
}
|
||||||
142
idd/LGIdd/capture/CFrameGraph.h
Normal file
142
idd/LGIdd/capture/CFrameGraph.h
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "postprocess/D12FrameFormat.h"
|
||||||
|
#include "transport/FrameProfile.h"
|
||||||
|
#include "transport/TransportConfig.h"
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static const unsigned FRAME_DAMAGE_MAX = 256;
|
||||||
|
static const unsigned FRAME_GRAPH_ROOT = UINT_MAX;
|
||||||
|
static const unsigned FRAME_GRAPH_MAX_NODES =
|
||||||
|
1 + 2 * TRANSPORT_MAX_INSTANCES;
|
||||||
|
|
||||||
|
enum class FrameOp : uint8_t
|
||||||
|
{
|
||||||
|
SRC,
|
||||||
|
SDR,
|
||||||
|
SCRGB,
|
||||||
|
HDR10,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class FrameDamage : uint8_t
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
RECTS,
|
||||||
|
FULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GraphCfg
|
||||||
|
{
|
||||||
|
GpuMode mode = GpuMode::HARDWARE;
|
||||||
|
LUID adapter = {};
|
||||||
|
unsigned srcWidth = 0;
|
||||||
|
unsigned srcHeight = 0;
|
||||||
|
FrameProfile src;
|
||||||
|
unsigned width = 0;
|
||||||
|
unsigned height = 0;
|
||||||
|
FrameProfile checkpoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Frame
|
||||||
|
{
|
||||||
|
bool Same(const GraphCfg& left, const GraphCfg& right);
|
||||||
|
bool Valid(FrameDamage damage, const RECT * rects, unsigned count,
|
||||||
|
unsigned width, unsigned height);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GraphNode
|
||||||
|
{
|
||||||
|
FrameOp op = FrameOp::SRC;
|
||||||
|
unsigned parent = FRAME_GRAPH_ROOT;
|
||||||
|
unsigned refs = 0;
|
||||||
|
unsigned width = 0;
|
||||||
|
unsigned height = 0;
|
||||||
|
FrameProfile profile;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GraphLeaf
|
||||||
|
{
|
||||||
|
BackendId id = 0;
|
||||||
|
uint32_t epoch = 0;
|
||||||
|
unsigned node = 0;
|
||||||
|
bool required = false;
|
||||||
|
bool primary = false;
|
||||||
|
FrameCfg cfg;
|
||||||
|
};
|
||||||
|
|
||||||
|
// FrameDesc is resource-free. It can cross graph nodes without retaining the
|
||||||
|
// acquired IddCx texture and is paired with owned texture storage separately.
|
||||||
|
struct FrameDesc
|
||||||
|
{
|
||||||
|
uint64_t serial = 0;
|
||||||
|
uint64_t captureTime = 0;
|
||||||
|
FrameDamage damage = FrameDamage::NONE;
|
||||||
|
RECT rects[FRAME_DAMAGE_MAX] = {};
|
||||||
|
unsigned count = 0;
|
||||||
|
D12FrameFormat format = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LeafDesc
|
||||||
|
{
|
||||||
|
BackendId id = 0;
|
||||||
|
uint32_t epoch = 0;
|
||||||
|
unsigned node = 0;
|
||||||
|
FrameProfile profile;
|
||||||
|
FrameDesc frame = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class CFrameGraph
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
GraphCfg m_cfg;
|
||||||
|
GraphNode m_nodes[FRAME_GRAPH_MAX_NODES] = {};
|
||||||
|
GraphLeaf m_leaves[TRANSPORT_MAX_INSTANCES] = {};
|
||||||
|
unsigned m_nodeCount = 0;
|
||||||
|
unsigned m_leafCount = 0;
|
||||||
|
bool m_begun = false;
|
||||||
|
bool m_sealed = false;
|
||||||
|
|
||||||
|
unsigned Find(FrameOp op, unsigned parent, unsigned width, unsigned height,
|
||||||
|
const FrameProfile& profile) const;
|
||||||
|
unsigned AddNode(FrameOp op, unsigned parent, unsigned width,
|
||||||
|
unsigned height,
|
||||||
|
const FrameProfile& profile);
|
||||||
|
unsigned Checkpoint(const FrameProfile& profile);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void Reset();
|
||||||
|
bool Begin(const GraphCfg& cfg);
|
||||||
|
bool Can(const FrameCfg& cfg) const;
|
||||||
|
bool Add(BackendId id, uint32_t epoch, bool required, bool primary,
|
||||||
|
const FrameCfg& cfg);
|
||||||
|
bool Seal();
|
||||||
|
bool Same(const GraphCfg& cfg) const;
|
||||||
|
bool Desc(unsigned leaf, const FrameDesc& frame, LeafDesc& desc) const;
|
||||||
|
|
||||||
|
const GraphCfg& Cfg() const { return m_cfg; }
|
||||||
|
const GraphNode * Nodes(unsigned& count) const;
|
||||||
|
const GraphLeaf * Leaves(unsigned& count) const;
|
||||||
|
};
|
||||||
@@ -40,6 +40,34 @@
|
|||||||
|
|
||||||
static const uint32_t HDR_PQ_MIN_LUMINANCE = 50;
|
static const uint32_t HDR_PQ_MIN_LUMINANCE = 50;
|
||||||
static const uint32_t HDR_PQ_MAX_LUMINANCE = 10000;
|
static const uint32_t HDR_PQ_MAX_LUMINANCE = 10000;
|
||||||
|
static const uint64_t GRAPH_RETRY_NS = 250000000ULL;
|
||||||
|
|
||||||
|
static bool MakeGraphCfg(const D12FrameFormat& source,
|
||||||
|
const D12FrameFormat& checkpoint, bool software,
|
||||||
|
const LUID& adapter, GraphCfg& cfg)
|
||||||
|
{
|
||||||
|
if (!source.width || !source.height ||
|
||||||
|
source.desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D ||
|
||||||
|
!checkpoint.width || !checkpoint.height ||
|
||||||
|
checkpoint.desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
FrameProfile src;
|
||||||
|
FrameProfile output;
|
||||||
|
if (!D12::Profile(source, FrameStorage::D3D12_TEXTURE, src) ||
|
||||||
|
!D12::Profile(checkpoint, FrameStorage::D3D12_TEXTURE, output))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
cfg.mode = software ? GpuMode::SOFTWARE : GpuMode::HARDWARE;
|
||||||
|
cfg.adapter = adapter;
|
||||||
|
cfg.srcWidth = source.width;
|
||||||
|
cfg.srcHeight = source.height;
|
||||||
|
cfg.src = src;
|
||||||
|
cfg.width = checkpoint.width;
|
||||||
|
cfg.height = checkpoint.height;
|
||||||
|
cfg.checkpoint = output;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
CSwapChainProcessor::CSwapChainProcessor(CMonitorContext * monitorContext,
|
CSwapChainProcessor::CSwapChainProcessor(CMonitorContext * monitorContext,
|
||||||
UINT64 assignmentGeneration, IDDCX_MONITOR monitor,
|
UINT64 assignmentGeneration, IDDCX_MONITOR monitor,
|
||||||
@@ -329,6 +357,8 @@ void CSwapChainProcessor::SwapChainThreadCore()
|
|||||||
if (WaitForSingleObject(m_terminateEvent.Get(), 0) == WAIT_OBJECT_0)
|
if (WaitForSingleObject(m_terminateEvent.Get(), 0) == WAIT_OBJECT_0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
CfgGraph();
|
||||||
|
|
||||||
UINT frameNumber = 0;
|
UINT frameNumber = 0;
|
||||||
UINT dirtyRectCount = 0;
|
UINT dirtyRectCount = 0;
|
||||||
UINT moveRegionCount = 0;
|
UINT moveRegionCount = 0;
|
||||||
@@ -413,6 +443,7 @@ void CSwapChainProcessor::SwapChainThreadCore()
|
|||||||
// Every acquired frame must be finished before the next acquire, even if
|
// Every acquired frame must be finished before the next acquire, even if
|
||||||
// its presentation number was a duplicate and no work was submitted.
|
// its presentation number was a duplicate and no work was submitted.
|
||||||
hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain);
|
hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain);
|
||||||
|
surface.Reset();
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
// A lost path is normal (mode change/topology rebuild); Windows
|
// A lost path is normal (mode change/topology rebuild); Windows
|
||||||
@@ -493,6 +524,46 @@ bool CSwapChainProcessor::GetContentHDRMetadata(D12FrameFormat& format) const
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSwapChainProcessor::QueueGraph(const D12FrameFormat& source,
|
||||||
|
const D12FrameFormat& checkpoint)
|
||||||
|
{
|
||||||
|
GraphCfg cfg;
|
||||||
|
if (!MakeGraphCfg(
|
||||||
|
source, checkpoint, m_dx11Device->IsSoftware(),
|
||||||
|
m_renderAdapter, cfg))
|
||||||
|
return;
|
||||||
|
if (m_haveGraphCfg && Frame::Same(m_graphCfg, cfg))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_graphCfg = cfg;
|
||||||
|
m_haveGraphCfg = true;
|
||||||
|
m_graphPending = true;
|
||||||
|
m_graphRetryAt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSwapChainProcessor::CfgGraph()
|
||||||
|
{
|
||||||
|
if (!m_graphPending)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const uint64_t now = CFrameScheduler::Nanotime();
|
||||||
|
if (now < m_graphRetryAt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_graphPending = false;
|
||||||
|
const CfgResult result =
|
||||||
|
m_devContext->GetTransport().Cfg(m_graphCfg, m_graph);
|
||||||
|
if (result == CfgResult::ACCEPTED)
|
||||||
|
{
|
||||||
|
m_graphRetryAt = 0;
|
||||||
|
}
|
||||||
|
else if (result == CfgResult::RETRY)
|
||||||
|
{
|
||||||
|
m_graphPending = true;
|
||||||
|
m_graphRetryAt = now + GRAPH_RETRY_NS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer,
|
bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer,
|
||||||
unsigned dirtyRectCount, unsigned moveRegionCount,
|
unsigned dirtyRectCount, unsigned moveRegionCount,
|
||||||
DXGI_COLOR_SPACE_TYPE colorSpace, UINT sdrWhiteLevel,
|
DXGI_COLOR_SPACE_TYPE colorSpace, UINT sdrWhiteLevel,
|
||||||
@@ -732,6 +803,10 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
|||||||
|
|
||||||
m_postProcessors[0].GetTimingToken(
|
m_postProcessors[0].GetTimingToken(
|
||||||
&timingEffectIndex, &timingToken);
|
&timingEffectIndex, &timingToken);
|
||||||
|
|
||||||
|
const D12FrameFormat& graphFormat =
|
||||||
|
m_postProcessors[0].GetTextureFormat();
|
||||||
|
QueueGraph(srcFormat, graphFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsReconfigure || postProcessFormatChanged || frameMetadataChanged)
|
if (needsReconfigure || postProcessFormatChanged || frameMetadataChanged)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "d3d/CD3D12Device.h"
|
#include "d3d/CD3D12Device.h"
|
||||||
#include "display/IddCxCompat.h"
|
#include "display/IddCxCompat.h"
|
||||||
#include "d3d/CInteropResourcePool.h"
|
#include "d3d/CInteropResourcePool.h"
|
||||||
|
#include "capture/CFrameGraph.h"
|
||||||
#include "capture/CFrameProcessor.h"
|
#include "capture/CFrameProcessor.h"
|
||||||
#include "postprocess/D12FrameFormat.h"
|
#include "postprocess/D12FrameFormat.h"
|
||||||
#include "postprocess/CPostProcessor.h"
|
#include "postprocess/CPostProcessor.h"
|
||||||
@@ -56,6 +57,11 @@ private:
|
|||||||
HANDLE m_newFrameEvent;
|
HANDLE m_newFrameEvent;
|
||||||
|
|
||||||
CInteropResourcePool m_resPool;
|
CInteropResourcePool m_resPool;
|
||||||
|
CFrameGraph m_graph;
|
||||||
|
GraphCfg m_graphCfg;
|
||||||
|
bool m_haveGraphCfg = false;
|
||||||
|
bool m_graphPending = false;
|
||||||
|
uint64_t m_graphRetryAt = 0;
|
||||||
CPostProcessor m_postProcessors[CAPTURE_PIPELINE_SLOTS];
|
CPostProcessor m_postProcessors[CAPTURE_PIPELINE_SLOTS];
|
||||||
std::unique_ptr<CFrameProcessor> m_frameProcessor;
|
std::unique_ptr<CFrameProcessor> m_frameProcessor;
|
||||||
// Reconfiguration is exclusive while per-candidate recording is shared.
|
// Reconfiguration is exclusive while per-candidate recording is shared.
|
||||||
@@ -93,6 +99,9 @@ private:
|
|||||||
void UpdateHDRMetadata(const IDDCX_METADATA2& metadata);
|
void UpdateHDRMetadata(const IDDCX_METADATA2& metadata);
|
||||||
#endif
|
#endif
|
||||||
bool GetContentHDRMetadata(D12FrameFormat& format) const;
|
bool GetContentHDRMetadata(D12FrameFormat& format) const;
|
||||||
|
void QueueGraph(const D12FrameFormat& source,
|
||||||
|
const D12FrameFormat& checkpoint);
|
||||||
|
void CfgGraph();
|
||||||
bool SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer,
|
bool SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer,
|
||||||
unsigned dirtyRectCount, unsigned moveRegionCount,
|
unsigned dirtyRectCount, unsigned moveRegionCount,
|
||||||
DXGI_COLOR_SPACE_TYPE colorSpace, UINT sdrWhiteLevel,
|
DXGI_COLOR_SPACE_TYPE colorSpace, UINT sdrWhiteLevel,
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ void CPostProcessor::Reset()
|
|||||||
m_device.Reset();
|
m_device.Reset();
|
||||||
m_srcFormat = {};
|
m_srcFormat = {};
|
||||||
m_dstFormat = {};
|
m_dstFormat = {};
|
||||||
|
m_texFormat = {};
|
||||||
m_copyLayout = {};
|
m_copyLayout = {};
|
||||||
m_copyEffect = nullptr;
|
m_copyEffect = nullptr;
|
||||||
m_frameSize = 0;
|
m_frameSize = 0;
|
||||||
@@ -173,6 +174,7 @@ bool CPostProcessor::Configure(const D12FrameFormat& srcFormat,
|
|||||||
// Propagate it without recreating resources or post-processing state.
|
// Propagate it without recreating resources or post-processing state.
|
||||||
D12::CopyHdr(m_srcFormat, srcFormat);
|
D12::CopyHdr(m_srcFormat, srcFormat);
|
||||||
D12::CopyHdr(m_dstFormat, srcFormat);
|
D12::CopyHdr(m_dstFormat, srcFormat);
|
||||||
|
D12::CopyHdr(m_texFormat, srcFormat);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,6 +183,7 @@ bool CPostProcessor::Configure(const D12FrameFormat& srcFormat,
|
|||||||
|
|
||||||
D12FrameFormat oldDst = m_dstFormat;
|
D12FrameFormat oldDst = m_dstFormat;
|
||||||
D12FrameFormat cur = srcFormat;
|
D12FrameFormat cur = srcFormat;
|
||||||
|
D12FrameFormat tex = srcFormat;
|
||||||
CPostProcessEffect * outputEffect = nullptr;
|
CPostProcessEffect * outputEffect = nullptr;
|
||||||
bool effectsActive = false;
|
bool effectsActive = false;
|
||||||
|
|
||||||
@@ -193,6 +196,8 @@ bool CPostProcessor::Configure(const D12FrameFormat& srcFormat,
|
|||||||
effect->Enabled = true;
|
effect->Enabled = true;
|
||||||
effectsActive = true;
|
effectsActive = true;
|
||||||
cur = dst;
|
cur = dst;
|
||||||
|
if (dst.desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D)
|
||||||
|
tex = dst;
|
||||||
outputEffect = effect.get();
|
outputEffect = effect.get();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -249,6 +254,7 @@ bool CPostProcessor::Configure(const D12FrameFormat& srcFormat,
|
|||||||
|
|
||||||
m_srcFormat = srcFormat;
|
m_srcFormat = srcFormat;
|
||||||
m_dstFormat = cur;
|
m_dstFormat = cur;
|
||||||
|
m_texFormat = tex;
|
||||||
m_copyLayout = copyLayout;
|
m_copyLayout = copyLayout;
|
||||||
m_copyEffect = copyEffect;
|
m_copyEffect = copyEffect;
|
||||||
m_frameSize = frameSize;
|
m_frameSize = frameSize;
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ private:
|
|||||||
std::vector<std::unique_ptr<CPostProcessEffect>> m_effects;
|
std::vector<std::unique_ptr<CPostProcessEffect>> m_effects;
|
||||||
D12FrameFormat m_srcFormat = {};
|
D12FrameFormat m_srcFormat = {};
|
||||||
D12FrameFormat m_dstFormat = {};
|
D12FrameFormat m_dstFormat = {};
|
||||||
|
D12FrameFormat m_texFormat = {};
|
||||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT m_copyLayout = {};
|
D3D12_PLACED_SUBRESOURCE_FOOTPRINT m_copyLayout = {};
|
||||||
CPostProcessEffect * m_copyEffect = nullptr;
|
CPostProcessEffect * m_copyEffect = nullptr;
|
||||||
size_t m_frameSize = 0;
|
size_t m_frameSize = 0;
|
||||||
@@ -135,6 +136,7 @@ public:
|
|||||||
unsigned * nbDirtyRects);
|
unsigned * nbDirtyRects);
|
||||||
|
|
||||||
const D12FrameFormat& GetOutputFormat() const { return m_dstFormat; }
|
const D12FrameFormat& GetOutputFormat() const { return m_dstFormat; }
|
||||||
|
const D12FrameFormat& GetTextureFormat() const { return m_texFormat; }
|
||||||
bool HasActiveEffects() const { return m_effectsActive; }
|
bool HasActiveEffects() const { return m_effectsActive; }
|
||||||
void GetTimingToken(unsigned * effectIndex, uint64_t * token) const;
|
void GetTimingToken(unsigned * effectIndex, uint64_t * token) const;
|
||||||
void RecordTiming(unsigned effectIndex, uint64_t token,
|
void RecordTiming(unsigned effectIndex, uint64_t token,
|
||||||
|
|||||||
@@ -71,6 +71,27 @@ std::shared_ptr<const D12ColorTransform> D12::Transform(
|
|||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DXGI_FORMAT D12::Dxgi(FramePixel pixel)
|
||||||
|
{
|
||||||
|
switch (pixel)
|
||||||
|
{
|
||||||
|
case FramePixel::BGRA8:
|
||||||
|
return DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
case FramePixel::RGBA8:
|
||||||
|
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
case FramePixel::RGB10A2:
|
||||||
|
return DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||||
|
case FramePixel::RGBA16F:
|
||||||
|
return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||||
|
}
|
||||||
|
return DXGI_FORMAT_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameType D12::Type(FramePixel pixel)
|
||||||
|
{
|
||||||
|
return Type(Dxgi(pixel));
|
||||||
|
}
|
||||||
|
|
||||||
FrameType D12::Type(DXGI_FORMAT format)
|
FrameType D12::Type(DXGI_FORMAT format)
|
||||||
{
|
{
|
||||||
switch (format)
|
switch (format)
|
||||||
@@ -88,6 +109,75 @@ FrameType D12::Type(DXGI_FORMAT format)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool D12::Profile(const D12FrameFormat& format, FrameStorage storage,
|
||||||
|
FrameProfile& profile)
|
||||||
|
{
|
||||||
|
if ((format.hdrPQ && !format.hdr) || !Frame::Valid(storage))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
FrameProfile result;
|
||||||
|
result.storage = storage;
|
||||||
|
if (!format.hdr)
|
||||||
|
{
|
||||||
|
result.signal = FrameSignal::SRGB;
|
||||||
|
if (format.format == FRAME_TYPE_BGRA)
|
||||||
|
result.pixel = FramePixel::BGRA8;
|
||||||
|
else if (format.format == FRAME_TYPE_RGBA)
|
||||||
|
result.pixel = FramePixel::RGBA8;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (format.hdrPQ)
|
||||||
|
{
|
||||||
|
if (format.format != FRAME_TYPE_RGBA10)
|
||||||
|
return false;
|
||||||
|
result.pixel = FramePixel::RGB10A2;
|
||||||
|
result.signal = FrameSignal::PQ_BT2020;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (format.format != FRAME_TYPE_RGBA16F)
|
||||||
|
return false;
|
||||||
|
result.pixel = FramePixel::RGBA16F;
|
||||||
|
result.signal = FrameSignal::SCRGB_LINEAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.desc.Format != Dxgi(result.pixel))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
profile = result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D12::Set(D12FrameFormat& format, const FrameProfile& profile,
|
||||||
|
unsigned width, unsigned height, D3D12_RESOURCE_FLAGS flags)
|
||||||
|
{
|
||||||
|
if (!width || !height || profile.storage != FrameStorage::D3D12_TEXTURE ||
|
||||||
|
!Frame::Valid(profile))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
format.desc = {};
|
||||||
|
format.desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||||
|
format.desc.Width = width;
|
||||||
|
format.desc.Height = height;
|
||||||
|
format.desc.DepthOrArraySize = 1;
|
||||||
|
format.desc.MipLevels = 1;
|
||||||
|
format.desc.Format = Dxgi(profile.pixel);
|
||||||
|
format.desc.SampleDesc.Count = 1;
|
||||||
|
format.desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||||
|
format.desc.Flags = flags;
|
||||||
|
format.dataWidth = width;
|
||||||
|
format.dataHeight = height;
|
||||||
|
format.pitch = 0;
|
||||||
|
format.width = width;
|
||||||
|
format.height = height;
|
||||||
|
format.format = Type(profile.pixel);
|
||||||
|
format.hdr = profile.signal != FrameSignal::SRGB;
|
||||||
|
format.hdrPQ = profile.signal == FrameSignal::PQ_BT2020;
|
||||||
|
return format.desc.Format != DXGI_FORMAT_UNKNOWN &&
|
||||||
|
format.format != FRAME_TYPE_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
void D12::CopyHdr(D12FrameFormat& dst, const D12FrameFormat& src)
|
void D12::CopyHdr(D12FrameFormat& dst, const D12FrameFormat& src)
|
||||||
{
|
{
|
||||||
dst.hdrMetadata = src.hdrMetadata;
|
dst.hdrMetadata = src.hdrMetadata;
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "transport/FrameProfile.h"
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <d3d12.h>
|
#include <d3d12.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -85,7 +87,15 @@ namespace D12
|
|||||||
NO_FLAGS,
|
NO_FLAGS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DXGI_FORMAT Dxgi(FramePixel pixel);
|
||||||
FrameType Type(DXGI_FORMAT format);
|
FrameType Type(DXGI_FORMAT format);
|
||||||
|
FrameType Type(FramePixel pixel);
|
||||||
|
|
||||||
|
bool Profile(const D12FrameFormat& format, FrameStorage storage,
|
||||||
|
FrameProfile& profile);
|
||||||
|
bool Set(D12FrameFormat& format, const FrameProfile& profile,
|
||||||
|
unsigned width, unsigned height,
|
||||||
|
D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE);
|
||||||
void CopyHdr(D12FrameFormat& dst, const D12FrameFormat& src);
|
void CopyHdr(D12FrameFormat& dst, const D12FrameFormat& src);
|
||||||
std::shared_ptr<const D12ColorTransform> Transform(
|
std::shared_ptr<const D12ColorTransform> Transform(
|
||||||
const std::shared_ptr<const D12ColorTransform>& transform);
|
const std::shared_ptr<const D12ColorTransform>& transform);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "transport/CTransportManager.h"
|
#include "transport/CTransportManager.h"
|
||||||
|
|
||||||
|
#include "capture/CFrameGraph.h"
|
||||||
#include "CDebug.h"
|
#include "CDebug.h"
|
||||||
#include "Seq.h"
|
#include "Seq.h"
|
||||||
|
|
||||||
@@ -993,6 +994,190 @@ bool CTransportManager::Setup(size_t alignment)
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CfgResult CTransportManager::Cfg(
|
||||||
|
const GraphCfg& cfg, CFrameGraph& graph)
|
||||||
|
{
|
||||||
|
CFrameGraph next;
|
||||||
|
if (!next.Begin(cfg))
|
||||||
|
return CfgResult::REJECTED;
|
||||||
|
if (!BeginPhase(Phase::CFG, true))
|
||||||
|
return CfgResult::RETRY;
|
||||||
|
|
||||||
|
struct Route
|
||||||
|
{
|
||||||
|
Entry * entry = nullptr;
|
||||||
|
std::shared_ptr<ITransport> transport;
|
||||||
|
BackendId id = 0;
|
||||||
|
uint32_t epoch = 0;
|
||||||
|
bool required = false;
|
||||||
|
bool primary = false;
|
||||||
|
bool prepared = false;
|
||||||
|
bool eligible = false;
|
||||||
|
FrameProfile profiles[FRAME_PROFILE_MAX] = {};
|
||||||
|
unsigned profileCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Route routes[FRAME_MAX_SINKS];
|
||||||
|
unsigned routeCount = 0;
|
||||||
|
CfgResult result = CfgResult::ACCEPTED;
|
||||||
|
|
||||||
|
Entry * entries[FRAME_MAX_SINKS] = {};
|
||||||
|
const unsigned count = Entries(entries);
|
||||||
|
for (unsigned i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
Entry& entry = *entries[i];
|
||||||
|
bool frameService = false;
|
||||||
|
bool required = false;
|
||||||
|
{
|
||||||
|
CSRWSharedLock entryLock(entry.lock);
|
||||||
|
frameService =
|
||||||
|
(entry.config.services & TRANSPORT_SERVICE_FRAME) != 0;
|
||||||
|
required = entry.required;
|
||||||
|
}
|
||||||
|
if (!frameService)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!BeginCall(entry, Call::CFG, true))
|
||||||
|
{
|
||||||
|
if (required)
|
||||||
|
{
|
||||||
|
result = CfgResult::RETRY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Route& route = routes[routeCount++];
|
||||||
|
route.entry = &entry;
|
||||||
|
State state;
|
||||||
|
bool frameAbsent = false;
|
||||||
|
{
|
||||||
|
CSRWSharedLock entryLock(entry.lock);
|
||||||
|
route.transport = entry.transport;
|
||||||
|
route.id = entry.id;
|
||||||
|
route.epoch = entry.epoch;
|
||||||
|
route.required = entry.required;
|
||||||
|
route.primary = entry.primary;
|
||||||
|
state = entry.state;
|
||||||
|
frameAbsent = entry.frameAbsent;
|
||||||
|
}
|
||||||
|
|
||||||
|
route.eligible = route.transport && !frameAbsent &&
|
||||||
|
(state == State::INITIALIZED || state == State::READY);
|
||||||
|
if (!route.eligible)
|
||||||
|
{
|
||||||
|
if (!route.required &&
|
||||||
|
(frameAbsent || state == State::FAILED))
|
||||||
|
continue;
|
||||||
|
result = frameAbsent ? CfgResult::REJECTED :
|
||||||
|
(state == State::FAILED ? CfgResult::FAILED : CfgResult::RETRY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned profileCount = 0;
|
||||||
|
const FrameProfile * profiles =
|
||||||
|
route.transport->Profiles(profileCount);
|
||||||
|
if (profileCount > FRAME_PROFILE_MAX ||
|
||||||
|
(profileCount && !profiles))
|
||||||
|
{
|
||||||
|
route.eligible = false;
|
||||||
|
if (route.required)
|
||||||
|
{
|
||||||
|
result = CfgResult::FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
route.profileCount = profileCount;
|
||||||
|
for (unsigned profile = 0; profile < profileCount; ++profile)
|
||||||
|
route.profiles[profile] = profiles[profile];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == CfgResult::ACCEPTED)
|
||||||
|
for (unsigned i = 0; i < routeCount; ++i)
|
||||||
|
{
|
||||||
|
Route& route = routes[i];
|
||||||
|
if (!route.eligible)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CfgResult routeResult = CfgResult::NEXT;
|
||||||
|
for (unsigned profileIndex = 0;
|
||||||
|
profileIndex < route.profileCount; ++profileIndex)
|
||||||
|
{
|
||||||
|
const FrameProfile& profile = route.profiles[profileIndex];
|
||||||
|
FrameCfg candidate;
|
||||||
|
candidate.mode = cfg.mode;
|
||||||
|
candidate.adapter = cfg.adapter;
|
||||||
|
candidate.width = cfg.width;
|
||||||
|
candidate.height = cfg.height;
|
||||||
|
candidate.profile = profile;
|
||||||
|
if (!next.Can(candidate))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
routeResult = route.transport->Probe(candidate);
|
||||||
|
if (routeResult == CfgResult::NEXT)
|
||||||
|
continue;
|
||||||
|
if (routeResult != CfgResult::ACCEPTED)
|
||||||
|
break;
|
||||||
|
|
||||||
|
routeResult = route.transport->Prepare(candidate);
|
||||||
|
if (routeResult == CfgResult::NEXT)
|
||||||
|
{
|
||||||
|
route.transport->Abort();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (routeResult != CfgResult::ACCEPTED)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!next.Add(route.id, route.epoch, route.required,
|
||||||
|
route.primary, candidate))
|
||||||
|
{
|
||||||
|
route.transport->Abort();
|
||||||
|
routeResult = CfgResult::FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
route.prepared = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route.prepared)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
route.transport->Abort();
|
||||||
|
if (routeResult == CfgResult::RETRY)
|
||||||
|
{
|
||||||
|
result = CfgResult::RETRY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (route.required)
|
||||||
|
{
|
||||||
|
result = routeResult == CfgResult::NEXT ?
|
||||||
|
CfgResult::REJECTED : routeResult;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == CfgResult::ACCEPTED && !next.Seal())
|
||||||
|
result = CfgResult::FAILED;
|
||||||
|
|
||||||
|
if (result == CfgResult::ACCEPTED)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < routeCount; ++i)
|
||||||
|
if (routes[i].prepared)
|
||||||
|
routes[i].transport->Commit();
|
||||||
|
graph = next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (unsigned i = routeCount; i > 0; --i)
|
||||||
|
if (routes[i - 1].prepared)
|
||||||
|
routes[i - 1].transport->Abort();
|
||||||
|
|
||||||
|
for (unsigned i = routeCount; i > 0; --i)
|
||||||
|
EndCall(*routes[i - 1].entry, routes[i - 1].transport);
|
||||||
|
EndPhase();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
ITransport::ProcessResult CTransportManager::Process(
|
ITransport::ProcessResult CTransportManager::Process(
|
||||||
ITransportActions& actions)
|
ITransportActions& actions)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,6 +33,9 @@
|
|||||||
static_assert(TRANSPORT_MAX_INSTANCES == FRAME_MAX_SINKS,
|
static_assert(TRANSPORT_MAX_INSTANCES == FRAME_MAX_SINKS,
|
||||||
"The transport and frame limits must match");
|
"The transport and frame limits must match");
|
||||||
|
|
||||||
|
class CFrameGraph;
|
||||||
|
struct GraphCfg;
|
||||||
|
|
||||||
class CTransportManager final : public FrameCaps
|
class CTransportManager final : public FrameCaps
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -51,6 +54,7 @@ private:
|
|||||||
OPEN,
|
OPEN,
|
||||||
INITIALIZE,
|
INITIALIZE,
|
||||||
SETUP,
|
SETUP,
|
||||||
|
CFG,
|
||||||
PROCESS,
|
PROCESS,
|
||||||
ACCESS,
|
ACCESS,
|
||||||
STOP,
|
STOP,
|
||||||
@@ -71,6 +75,7 @@ private:
|
|||||||
{
|
{
|
||||||
IDLE,
|
IDLE,
|
||||||
LIFECYCLE,
|
LIFECYCLE,
|
||||||
|
CFG,
|
||||||
PROCESS,
|
PROCESS,
|
||||||
RECOVERY,
|
RECOVERY,
|
||||||
ACCESS,
|
ACCESS,
|
||||||
@@ -168,6 +173,7 @@ public:
|
|||||||
OpenResult Open();
|
OpenResult Open();
|
||||||
bool Initialize();
|
bool Initialize();
|
||||||
bool Setup(size_t alignment);
|
bool Setup(size_t alignment);
|
||||||
|
CfgResult Cfg(const GraphCfg& cfg, CFrameGraph& graph);
|
||||||
ProcessResult Process(ITransportActions& actions);
|
ProcessResult Process(ITransportActions& actions);
|
||||||
void Stop();
|
void Stop();
|
||||||
void SyncRecovery();
|
void SyncRecovery();
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static const unsigned FRAME_PROFILE_MAX = 16;
|
||||||
|
|
||||||
enum class FrameStorage : uint8_t
|
enum class FrameStorage : uint8_t
|
||||||
{
|
{
|
||||||
D3D12_TEXTURE,
|
D3D12_TEXTURE,
|
||||||
|
|||||||
@@ -148,8 +148,9 @@ public:
|
|||||||
virtual void RecoveryStatus(const SourceKey&, uint64_t, uint32_t,
|
virtual void RecoveryStatus(const SourceKey&, uint64_t, uint32_t,
|
||||||
bool, Recovery, uint32_t) {}
|
bool, Recovery, uint32_t) {}
|
||||||
|
|
||||||
// Profiles is an immutable, ordered preference list whose pointer remains
|
// Profiles is an immutable, ordered preference list of at most
|
||||||
// valid for the lifetime of this instance.
|
// FRAME_PROFILE_MAX entries whose pointer remains valid for the lifetime
|
||||||
|
// of this instance.
|
||||||
// Probe has no side effects. Prepare changes pending state only; Commit
|
// Probe has no side effects. Prepare changes pending state only; Commit
|
||||||
// promotes it without failure, while Abort preserves the active route.
|
// promotes it without failure, while Abort preserves the active route.
|
||||||
virtual const FrameProfile * Profiles(unsigned& count) const = 0;
|
virtual const FrameProfile * Profiles(unsigned& count) const = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user