mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 07:01:30 +00:00
[idd] capture: version frame graph changes
This commit is contained in:
@@ -33,6 +33,8 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
static const uint64_t ROUTE_RETRY_DELAY_MS = 500;
|
||||
|
||||
template<typename T, std::size_t N>
|
||||
T& Append(T (&items)[N], unsigned& count)
|
||||
{
|
||||
@@ -50,6 +52,13 @@ struct CTexSet
|
||||
{
|
||||
struct Route
|
||||
{
|
||||
enum class State : uint8_t
|
||||
{
|
||||
ACTIVE,
|
||||
FAULTED,
|
||||
DROPPED,
|
||||
};
|
||||
|
||||
std::shared_ptr<ITransport> owner;
|
||||
ITexSink * sink = nullptr;
|
||||
BackendId id = 0;
|
||||
@@ -60,8 +69,7 @@ struct CTexSet
|
||||
FrameCfg cfg;
|
||||
bool required = false;
|
||||
bool primary = false;
|
||||
bool active = false;
|
||||
bool dropped = false;
|
||||
State state = State::ACTIVE;
|
||||
CfgResult fault = CfgResult::ACCEPTED;
|
||||
unsigned calls = 0;
|
||||
HANDLE idle = nullptr;
|
||||
@@ -184,7 +192,8 @@ bool CTexHub::Enter(const FrameIn& frame, bool lease,
|
||||
|
||||
CSRWExclusiveLock lock(set->lock);
|
||||
route = Find(*set, frame);
|
||||
if (route >= set->count || !set->routes[route].active || !lease ||
|
||||
if (route >= set->count ||
|
||||
set->routes[route].state != CTexSet::Route::State::ACTIVE || !lease ||
|
||||
frame.graph != set->generation)
|
||||
return false;
|
||||
|
||||
@@ -228,6 +237,30 @@ CfgResult CTexHub::Faulted(BackendId id, uint32_t epoch,
|
||||
return CfgResult::ACCEPTED;
|
||||
}
|
||||
|
||||
bool CTexHub::Active(uint64_t generation, BackendId id,
|
||||
uint32_t epoch, const FrameCfg& cfg) const
|
||||
{
|
||||
std::shared_ptr<CTexSet> set;
|
||||
{
|
||||
CSRWSharedLock lock(m_lock);
|
||||
set = m_active;
|
||||
}
|
||||
if (!set || !generation || set->generation != generation)
|
||||
return false;
|
||||
|
||||
CSRWSharedLock lock(set->lock);
|
||||
for (unsigned i = 0; i < set->count; ++i)
|
||||
{
|
||||
const CTexSet::Route& route = set->routes[i];
|
||||
if (route.id == id &&
|
||||
route.epoch == epoch &&
|
||||
route.state == CTexSet::Route::State::ACTIVE &&
|
||||
Frame::Same(route.cfg, cfg))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CTexHub::Rebind(BackendId id, uint32_t epoch)
|
||||
{
|
||||
if (!id || !epoch)
|
||||
@@ -243,6 +276,39 @@ void CTexHub::Rebind(BackendId id, uint32_t epoch)
|
||||
m_faults[i] = m_faults[--m_faultCount];
|
||||
m_faults[m_faultCount] = FaultRec {};
|
||||
}
|
||||
for (unsigned i = 0; i < m_failureCount;)
|
||||
{
|
||||
if (m_failures[i].id != id || m_failures[i].epoch != epoch)
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
m_failures[i] = m_failures[--m_failureCount];
|
||||
m_failures[m_failureCount] = Failure {};
|
||||
}
|
||||
}
|
||||
|
||||
void CTexHub::Retry(uint64_t now)
|
||||
{
|
||||
bool wake = false;
|
||||
{
|
||||
CSRWExclusiveLock lock(m_lock);
|
||||
for (unsigned i = 0; i < m_faultCount;)
|
||||
{
|
||||
const FaultRec& fault = m_faults[i];
|
||||
if (fault.result != CfgResult::REJECTED || !fault.retryAt ||
|
||||
now < fault.retryAt)
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
m_faults[i] = m_faults[--m_faultCount];
|
||||
m_faults[m_faultCount] = FaultRec {};
|
||||
wake = true;
|
||||
}
|
||||
}
|
||||
if (wake)
|
||||
Bump();
|
||||
}
|
||||
|
||||
void CTexHub::Leave(
|
||||
@@ -267,13 +333,14 @@ void CTexHub::Disable(const std::shared_ptr<CTexSet>& set,
|
||||
CTexSet::Route failed;
|
||||
{
|
||||
CSRWExclusiveLock lock(set->lock);
|
||||
if (route < set->count && !set->routes[route].dropped &&
|
||||
(set->routes[route].active ||
|
||||
if (route < set->count &&
|
||||
set->routes[route].state != CTexSet::Route::State::DROPPED &&
|
||||
(set->routes[route].state == CTexSet::Route::State::ACTIVE ||
|
||||
(result == PushResult::FAILED &&
|
||||
set->routes[route].fault == CfgResult::REJECTED)))
|
||||
{
|
||||
CTexSet::Route& target = set->routes[route];
|
||||
target.active = false;
|
||||
target.state = CTexSet::Route::State::FAULTED;
|
||||
target.fault = result == PushResult::FAILED ?
|
||||
CfgResult::FAILED : CfgResult::REJECTED;
|
||||
failed.id = target.id;
|
||||
@@ -286,11 +353,13 @@ void CTexHub::Disable(const std::shared_ptr<CTexSet>& set,
|
||||
return;
|
||||
|
||||
FaultRec record;
|
||||
record.id = failed.id;
|
||||
record.epoch = failed.epoch;
|
||||
record.cfg = failed.cfg;
|
||||
record.result = result == PushResult::FAILED ?
|
||||
record.id = failed.id;
|
||||
record.epoch = failed.epoch;
|
||||
record.cfg = failed.cfg;
|
||||
record.result = result == PushResult::FAILED ?
|
||||
CfgResult::FAILED : CfgResult::REJECTED;
|
||||
record.retryAt = result == PushResult::REJECTED ?
|
||||
GetTickCount64() + ROUTE_RETRY_DELAY_MS : 0;
|
||||
|
||||
bool wake = false;
|
||||
{
|
||||
@@ -303,6 +372,7 @@ void CTexHub::Disable(const std::shared_ptr<CTexSet>& set,
|
||||
m_faults[i].result != CfgResult::FAILED)
|
||||
{
|
||||
m_faults[i].result = CfgResult::FAILED;
|
||||
m_faults[i].retryAt = 0;
|
||||
wake = true;
|
||||
}
|
||||
if (result != PushResult::FAILED)
|
||||
@@ -438,7 +508,7 @@ CfgResult CTexHub::Prep(const CFrameGraph& graph,
|
||||
target.cfg = route.cfg;
|
||||
target.required = route.required;
|
||||
target.primary = route.primary;
|
||||
target.active = true;
|
||||
target.state = CTexSet::Route::State::ACTIVE;
|
||||
target.idle = CreateEvent(nullptr, TRUE, TRUE, nullptr);
|
||||
if (!target.idle)
|
||||
return CfgResult::FAILED;
|
||||
@@ -616,9 +686,8 @@ void CTexHub::Drop(BackendId id, uint32_t epoch)
|
||||
if (set->routes[i].id == id && set->routes[i].epoch == epoch)
|
||||
{
|
||||
CTexSet::Route& target = set->routes[i];
|
||||
changed |= target.active;
|
||||
target.active = false;
|
||||
target.dropped = true;
|
||||
changed |= target.state == CTexSet::Route::State::ACTIVE;
|
||||
target.state = CTexSet::Route::State::DROPPED;
|
||||
if (target.calls)
|
||||
{
|
||||
ResetEvent(target.idle);
|
||||
|
||||
@@ -71,10 +71,11 @@ private:
|
||||
|
||||
struct FaultRec
|
||||
{
|
||||
BackendId id = 0;
|
||||
uint32_t epoch = 0;
|
||||
FrameCfg cfg;
|
||||
CfgResult result = CfgResult::ACCEPTED;
|
||||
BackendId id = 0;
|
||||
uint32_t epoch = 0;
|
||||
FrameCfg cfg;
|
||||
CfgResult result = CfgResult::ACCEPTED;
|
||||
uint64_t retryAt = 0;
|
||||
};
|
||||
|
||||
struct Failure
|
||||
@@ -125,6 +126,9 @@ private:
|
||||
|
||||
CfgResult Faulted(BackendId id, uint32_t epoch,
|
||||
const FrameCfg& cfg) const;
|
||||
bool Active(uint64_t generation, BackendId id, uint32_t epoch,
|
||||
const FrameCfg& cfg) const;
|
||||
void Retry(uint64_t now);
|
||||
bool TakeFailure(BackendId& id, uint32_t& epoch);
|
||||
void Rebind(BackendId id, uint32_t epoch);
|
||||
|
||||
|
||||
@@ -30,8 +30,10 @@
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
static const uint64_t RETRY_DELAY_MS = 500;
|
||||
static const uint64_t SERVICE_RETRY_DELAY_MS = 250;
|
||||
static const uint64_t RETRY_DELAY_MS = 500;
|
||||
static const uint64_t FRAME_RETRY_DELAY_MS = 500;
|
||||
static const uint64_t SERVICE_RETRY_DELAY_MS = 250;
|
||||
static std::atomic<uint64_t> s_graphGeneration = 0;
|
||||
|
||||
class CSourceEvents final : public ITransportEvents
|
||||
{
|
||||
@@ -135,9 +137,25 @@ void CTransportManager::BumpFrameRev()
|
||||
Atomic::Next(m_frameRev, std::memory_order_release);
|
||||
}
|
||||
|
||||
uint64_t CTransportManager::NextGraph()
|
||||
void CTransportManager::ScheduleFrameRetry(Entry& entry)
|
||||
{
|
||||
return Seq::Inc(m_graphSerial);
|
||||
CSRWExclusiveLock entryLock(entry.lock);
|
||||
if (!entry.frameRetryAt)
|
||||
entry.frameRetryAt = GetTickCount64() + FRAME_RETRY_DELAY_MS;
|
||||
}
|
||||
|
||||
void CTransportManager::RetryFrame(Entry& entry, uint64_t now)
|
||||
{
|
||||
bool retry = false;
|
||||
{
|
||||
CSRWExclusiveLock entryLock(entry.lock);
|
||||
if (!entry.frameRetryAt || now < entry.frameRetryAt)
|
||||
return;
|
||||
entry.frameRetryAt = 0;
|
||||
retry = entry.state == State::READY && entry.frameAdded;
|
||||
}
|
||||
if (retry)
|
||||
BumpFrameRev();
|
||||
}
|
||||
|
||||
CTransportManager::~CTransportManager()
|
||||
@@ -771,6 +789,7 @@ void CTransportManager::RemoveServices(Entry& entry)
|
||||
entry.texSink = nullptr;
|
||||
entry.controlAdded = false;
|
||||
entry.inputAdded = false;
|
||||
entry.frameRetryAt = 0;
|
||||
}
|
||||
|
||||
m_input.RevokeInteraction(id, epoch);
|
||||
@@ -1098,13 +1117,14 @@ CfgResult CTransportManager::Cfg(const GraphCfg& cfg,
|
||||
|
||||
struct Route
|
||||
{
|
||||
Entry * entry = nullptr;
|
||||
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 selected = false;
|
||||
bool eligible = false;
|
||||
ITexSink * texSink = nullptr;
|
||||
FrameProfile profiles[FRAME_PROFILE_MAX] = {};
|
||||
@@ -1238,9 +1258,30 @@ CfgResult CTransportManager::Cfg(const GraphCfg& cfg,
|
||||
}
|
||||
}
|
||||
|
||||
const bool tex = route.texSink != nullptr;
|
||||
const GraphLeaf * previous = graph.FindLeaf(
|
||||
route.id, route.epoch, tex, candidate);
|
||||
if (previous && previous->required == route.required &&
|
||||
previous->primary == route.primary &&
|
||||
(!tex || m_tex.Active(graph.Generation(),
|
||||
route.id, route.epoch, candidate)))
|
||||
{
|
||||
if (!next.Add(route.id, route.epoch, route.required,
|
||||
route.primary, tex, graph.Same(cfg), candidate))
|
||||
{
|
||||
routeResult = CfgResult::FAILED;
|
||||
break;
|
||||
}
|
||||
routeResult = CfgResult::ACCEPTED;
|
||||
route.selected = true;
|
||||
break;
|
||||
}
|
||||
|
||||
routeResult = route.transport->Probe(candidate);
|
||||
if (routeResult == CfgResult::NEXT)
|
||||
continue;
|
||||
if (routeResult == CfgResult::REJECTED)
|
||||
ScheduleFrameRetry(*route.entry);
|
||||
if (routeResult != CfgResult::ACCEPTED)
|
||||
break;
|
||||
|
||||
@@ -1250,21 +1291,24 @@ CfgResult CTransportManager::Cfg(const GraphCfg& cfg,
|
||||
route.transport->Abort();
|
||||
continue;
|
||||
}
|
||||
if (routeResult == CfgResult::REJECTED)
|
||||
ScheduleFrameRetry(*route.entry);
|
||||
if (routeResult != CfgResult::ACCEPTED)
|
||||
break;
|
||||
|
||||
if (!next.Add(route.id, route.epoch, route.required,
|
||||
route.primary, route.texSink != nullptr, candidate))
|
||||
route.primary, tex, false, candidate))
|
||||
{
|
||||
route.transport->Abort();
|
||||
routeResult = CfgResult::FAILED;
|
||||
break;
|
||||
}
|
||||
route.prepared = true;
|
||||
route.selected = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (route.prepared)
|
||||
if (route.selected)
|
||||
continue;
|
||||
|
||||
route.transport->Abort();
|
||||
@@ -1285,14 +1329,14 @@ CfgResult CTransportManager::Cfg(const GraphCfg& cfg,
|
||||
result = CfgResult::FAILED;
|
||||
|
||||
if (result == CfgResult::ACCEPTED &&
|
||||
!next.Stamp(NextGraph()))
|
||||
!next.Stamp(Atomic::Next(s_graphGeneration)))
|
||||
result = CfgResult::FAILED;
|
||||
|
||||
CTexHub::Bind binds[FRAME_MAX_SINKS];
|
||||
unsigned bindCount = 0;
|
||||
if (result == CfgResult::ACCEPTED)
|
||||
for (unsigned i = 0; i < routeCount; ++i)
|
||||
if (routes[i].prepared)
|
||||
if (routes[i].selected)
|
||||
{
|
||||
CTexHub::Bind& bind = binds[bindCount++];
|
||||
bind.owner = routes[i].transport;
|
||||
@@ -1315,8 +1359,15 @@ CfgResult CTransportManager::Cfg(const GraphCfg& cfg,
|
||||
if (result == CfgResult::ACCEPTED)
|
||||
{
|
||||
for (unsigned i = 0; i < routeCount; ++i)
|
||||
{
|
||||
if (routes[i].prepared)
|
||||
routes[i].transport->Commit();
|
||||
if (routes[i].selected)
|
||||
{
|
||||
CSRWExclusiveLock entryLock(routes[i].entry->lock);
|
||||
routes[i].entry->frameRetryAt = 0;
|
||||
}
|
||||
}
|
||||
graph = next;
|
||||
m_tex.Commit(texStage);
|
||||
if (activationReady)
|
||||
@@ -1360,12 +1411,14 @@ ITransport::ProcessResult CTransportManager::Process(
|
||||
|
||||
const uint64_t now = GetTickCount64();
|
||||
m_recovery.Tick(now);
|
||||
m_tex.Retry(now);
|
||||
HandleServiceFailures();
|
||||
Entry * entries[FRAME_MAX_SINKS] = {};
|
||||
const unsigned count = Entries(entries);
|
||||
for (unsigned i = 0; i < count; ++i)
|
||||
{
|
||||
Entry& entry = *entries[i];
|
||||
RetryFrame(entry, now);
|
||||
if (!BeginCall(entry, Call::PROCESS, false))
|
||||
continue;
|
||||
|
||||
|
||||
@@ -103,20 +103,21 @@ private:
|
||||
State state = State::CLOSED;
|
||||
uint32_t epoch = 1;
|
||||
uint64_t retryAt = 0;
|
||||
bool controlAdded = false;
|
||||
bool controlFailed = false;
|
||||
bool controlAbsent = false;
|
||||
bool inputAdded = false;
|
||||
bool inputFailed = false;
|
||||
bool inputAbsent = false;
|
||||
bool frameAdded = false;
|
||||
bool frameLegacy = false;
|
||||
ITexSink * texSink = nullptr;
|
||||
bool frameAbsent = false;
|
||||
uint64_t serviceRetryAt = 0;
|
||||
bool exposed = false;
|
||||
bool setupDone = false;
|
||||
bool syncPending = false;
|
||||
bool controlAdded = false;
|
||||
bool controlFailed = false;
|
||||
bool controlAbsent = false;
|
||||
bool inputAdded = false;
|
||||
bool inputFailed = false;
|
||||
bool inputAbsent = false;
|
||||
bool frameAdded = false;
|
||||
bool frameLegacy = false;
|
||||
ITexSink * texSink = nullptr;
|
||||
bool frameAbsent = false;
|
||||
uint64_t frameRetryAt = 0;
|
||||
uint64_t serviceRetryAt = 0;
|
||||
bool exposed = false;
|
||||
bool setupDone = false;
|
||||
bool syncPending = false;
|
||||
bool recoveryAttached = false;
|
||||
std::shared_ptr<const FrameCaps> frameCaps;
|
||||
DirectFrameBufferMemory directMemory;
|
||||
@@ -143,7 +144,6 @@ private:
|
||||
bool m_started = false;
|
||||
bool m_stopping = false;
|
||||
bool m_stopped = false;
|
||||
uint64_t m_graphSerial = 0;
|
||||
|
||||
unsigned Entries(Entry * entries[FRAME_MAX_SINKS]) const;
|
||||
Entry * Primary() const;
|
||||
@@ -169,7 +169,8 @@ private:
|
||||
void RemoveServices(Entry& entry);
|
||||
void Expose(Entry& entry);
|
||||
void BumpFrameRev();
|
||||
uint64_t NextGraph();
|
||||
void ScheduleFrameRetry(Entry& entry);
|
||||
void RetryFrame(Entry& entry, uint64_t now);
|
||||
|
||||
public:
|
||||
CTransportManager();
|
||||
|
||||
Reference in New Issue
Block a user