[idd] capture: build frame processing graph

This commit is contained in:
Geoffrey McRae
2026-08-13 13:43:32 +10:00
parent 081dcf8879
commit 43d918b5f3
14 changed files with 824 additions and 2 deletions

View File

@@ -20,6 +20,7 @@
#include "transport/CTransportManager.h"
#include "capture/CFrameGraph.h"
#include "CDebug.h"
#include "Seq.h"
@@ -993,6 +994,190 @@ bool CTransportManager::Setup(size_t alignment)
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(
ITransportActions& actions)
{

View File

@@ -33,6 +33,9 @@
static_assert(TRANSPORT_MAX_INSTANCES == FRAME_MAX_SINKS,
"The transport and frame limits must match");
class CFrameGraph;
struct GraphCfg;
class CTransportManager final : public FrameCaps
{
public:
@@ -51,6 +54,7 @@ private:
OPEN,
INITIALIZE,
SETUP,
CFG,
PROCESS,
ACCESS,
STOP,
@@ -71,6 +75,7 @@ private:
{
IDLE,
LIFECYCLE,
CFG,
PROCESS,
RECOVERY,
ACCESS,
@@ -168,6 +173,7 @@ public:
OpenResult Open();
bool Initialize();
bool Setup(size_t alignment);
CfgResult Cfg(const GraphCfg& cfg, CFrameGraph& graph);
ProcessResult Process(ITransportActions& actions);
void Stop();
void SyncRecovery();

View File

@@ -23,6 +23,8 @@
#include <Windows.h>
#include <stdint.h>
static const unsigned FRAME_PROFILE_MAX = 16;
enum class FrameStorage : uint8_t
{
D3D12_TEXTURE,

View File

@@ -148,8 +148,9 @@ public:
virtual void RecoveryStatus(const SourceKey&, uint64_t, uint32_t,
bool, Recovery, uint32_t) {}
// Profiles is an immutable, ordered preference list whose pointer remains
// valid for the lifetime of this instance.
// Profiles is an immutable, ordered preference list of at most
// 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
// promotes it without failure, while Abort preserves the active route.
virtual const FrameProfile * Profiles(unsigned& count) const = 0;