Files
LookingGlass/idd/LGIdd/capture/CFrameGraph.h
2026-08-14 02:30:31 +10:00

187 lines
5.6 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
*/
#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 + 5 * TRANSPORT_MAX_INSTANCES;
enum class FrameOp : uint8_t
{
SRC,
CAL,
LUT,
SCALE,
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;
std::shared_ptr<const D12ColorTransform> transform;
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;
// refs covers every route; texRefs is the direct texture-route closure.
unsigned refs = 0;
unsigned texRefs = 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;
bool tex = false;
// Partial damage remains valid across the preceding graph generation.
bool continuous = false;
FrameCfg cfg;
};
struct GraphRouteName
{
BackendId id = 0;
uint32_t epoch = 0;
const wchar_t * name = nullptr;
};
// All products derived from one capture retain the same immutable content.
// It contains no acquired IddCx or Direct3D resource.
struct FrameContent
{
uint64_t serial = 0;
uint64_t captureTime = 0;
FrameDamage damage = FrameDamage::NONE;
RECT rects[FRAME_DAMAGE_MAX] = {};
unsigned count = 0;
D12FrameFormat format = {};
};
using FrameContentRef = std::shared_ptr<const FrameContent>;
// FrameDesc adds one graph node's representation and damage to the shared
// content identity. It remains resource-free.
struct FrameDesc
{
FrameContentRef content;
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] = {};
uint64_t m_generation = 0;
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);
void LogNode(unsigned node, const GraphRouteName * routes,
unsigned routeCount, bool * ancestry, unsigned depth, bool last) const;
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,
bool tex, bool continuous, const FrameCfg& cfg);
bool Seal();
bool Stamp(uint64_t generation);
bool Ready() const { return m_sealed && m_generation; }
void Log(const GraphRouteName * routes, unsigned routeCount) const;
bool Same(const GraphCfg& cfg) const;
const GraphLeaf * FindLeaf(BackendId id, uint32_t epoch, bool tex,
const FrameCfg& frame) const;
bool Want(FrameSignal signal) const;
bool Need(FrameOp op) const;
bool Shared(unsigned node) const;
bool Desc(unsigned node, const FrameContentRef& content,
FrameDesc& desc) const;
bool Desc(unsigned leaf, const FrameContentRef& content,
LeafDesc& desc) const;
const GraphCfg& Cfg() const { return m_cfg; }
uint64_t Generation() const { return Ready() ? m_generation : 0; }
const GraphNode * Nodes(unsigned& count) const;
const GraphLeaf * Leaves(unsigned& count) const;
};