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:
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;
|
||||
}
|
||||
Reference in New Issue
Block a user