mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 08:41:31 +00:00
[idd] scheduler: pace secondary frame delivery
This commit is contained in:
@@ -80,18 +80,22 @@ bool CFrameScheduler::ElectOwner(uint64_t now)
|
|||||||
Client * fastest = nullptr;
|
Client * fastest = nullptr;
|
||||||
Client * incumbent = FindClient(m_schedule.clientID);
|
Client * incumbent = FindClient(m_schedule.clientID);
|
||||||
unsigned subscribers = 0;
|
unsigned subscribers = 0;
|
||||||
|
bool clientExpired = false;
|
||||||
|
|
||||||
for (Client& client : m_clients)
|
for (Client& client : m_clients)
|
||||||
{
|
{
|
||||||
if (!client.subscribed)
|
if (client.active && client.expiry <= now)
|
||||||
|
{
|
||||||
|
client.active = false;
|
||||||
|
clientExpired = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!client.subscribed || !client.ownerCapable)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
++subscribers;
|
++subscribers;
|
||||||
if (!client.active || client.expiry <= now)
|
if (!client.active)
|
||||||
{
|
|
||||||
client.active = false;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (!fastest || client.period < fastest->period)
|
if (!fastest || client.period < fastest->period)
|
||||||
fastest = &client;
|
fastest = &client;
|
||||||
@@ -100,7 +104,8 @@ bool CFrameScheduler::ElectOwner(uint64_t now)
|
|||||||
if (!subscribers)
|
if (!subscribers)
|
||||||
fastest = nullptr;
|
fastest = nullptr;
|
||||||
|
|
||||||
if (fastest && incumbent && incumbent->subscribed && incumbent->active &&
|
if (fastest && incumbent && incumbent->subscribed &&
|
||||||
|
incumbent->ownerCapable && incumbent->active &&
|
||||||
incumbent->expiry > now &&
|
incumbent->expiry > now &&
|
||||||
incumbent->period <= fastest->period + fastest->period / 200)
|
incumbent->period <= fastest->period + fastest->period / 200)
|
||||||
fastest = incumbent;
|
fastest = incumbent;
|
||||||
@@ -110,6 +115,10 @@ bool CFrameScheduler::ElectOwner(uint64_t now)
|
|||||||
const uint32_t oldEpoch = m_schedule.epoch;
|
const uint32_t oldEpoch = m_schedule.epoch;
|
||||||
const uint64_t oldPeriod = m_schedule.period;
|
const uint64_t oldPeriod = m_schedule.period;
|
||||||
const uint64_t oldSlack = m_schedule.targetSlack;
|
const uint64_t oldSlack = m_schedule.targetSlack;
|
||||||
|
if (incumbent && incumbent->active &&
|
||||||
|
incumbent->generation == oldGeneration)
|
||||||
|
incumbent->nextDelivery = m_nextDeadline;
|
||||||
|
|
||||||
if (!fastest)
|
if (!fastest)
|
||||||
{
|
{
|
||||||
m_schedule = {};
|
m_schedule = {};
|
||||||
@@ -134,7 +143,9 @@ bool CFrameScheduler::ElectOwner(uint64_t now)
|
|||||||
++m_epoch;
|
++m_epoch;
|
||||||
m_schedule.epoch = m_epoch;
|
m_schedule.epoch = m_epoch;
|
||||||
}
|
}
|
||||||
m_nextDeadline = m_scheduling ? now + m_schedule.period : 0;
|
m_nextDeadline = m_scheduling ? fastest->nextDelivery : 0;
|
||||||
|
if (m_scheduling && !m_nextDeadline)
|
||||||
|
m_nextDeadline = now + m_schedule.period;
|
||||||
m_forceNext = m_scheduling;
|
m_forceNext = m_scheduling;
|
||||||
m_republishNext = m_scheduling;
|
m_republishNext = m_scheduling;
|
||||||
|
|
||||||
@@ -157,7 +168,8 @@ bool CFrameScheduler::ElectOwner(uint64_t now)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ownerChanged || oldGeneration != m_schedule.generation ||
|
return ownerChanged || oldGeneration != m_schedule.generation ||
|
||||||
oldPeriod != m_schedule.period || oldSlack != m_schedule.targetSlack;
|
oldPeriod != m_schedule.period || oldSlack != m_schedule.targetSlack ||
|
||||||
|
clientExpired;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrameScheduler::Reset()
|
void CFrameScheduler::Reset()
|
||||||
@@ -191,12 +203,29 @@ void CFrameScheduler::Reset()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CFrameScheduler::UpdateSubscribers(const uint32_t * clientIDs,
|
void CFrameScheduler::UpdateSubscribers(const uint32_t * clientIDs,
|
||||||
unsigned count, uint64_t now)
|
unsigned count, const uint32_t * ownerClientIDs, unsigned ownerCount,
|
||||||
|
uint64_t now)
|
||||||
{
|
{
|
||||||
AcquireSRWLockExclusive(&m_lock);
|
AcquireSRWLockExclusive(&m_lock);
|
||||||
|
|
||||||
|
uint32_t oldClientIDs [LGMP_MAX_CLIENTS] = {};
|
||||||
|
bool wasSubscribed [LGMP_MAX_CLIENTS] = {};
|
||||||
|
bool wasOwnerCapable[LGMP_MAX_CLIENTS] = {};
|
||||||
|
unsigned clientIndex = 0;
|
||||||
|
for (const Client& client : m_clients)
|
||||||
|
{
|
||||||
|
oldClientIDs[clientIndex] = client.clientID;
|
||||||
|
wasSubscribed[clientIndex] = client.subscribed;
|
||||||
|
wasOwnerCapable[clientIndex] = client.ownerCapable;
|
||||||
|
++clientIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subscribersChanged = false;
|
||||||
for (Client& client : m_clients)
|
for (Client& client : m_clients)
|
||||||
|
{
|
||||||
client.subscribed = false;
|
client.subscribed = false;
|
||||||
|
client.ownerCapable = false;
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < count; ++i)
|
for (unsigned i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
@@ -217,12 +246,31 @@ void CFrameScheduler::UpdateSubscribers(const uint32_t * clientIDs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < ownerCount; ++i)
|
||||||
|
{
|
||||||
|
Client * client = FindClient(ownerClientIDs[i]);
|
||||||
|
if (client && client->subscribed)
|
||||||
|
client->ownerCapable = true;
|
||||||
|
}
|
||||||
|
|
||||||
for (Client& client : m_clients)
|
for (Client& client : m_clients)
|
||||||
if (client.clientID && !client.subscribed &&
|
if (client.clientID && !client.subscribed &&
|
||||||
(client.subscriptionSeen || !client.active || client.expiry <= now))
|
(client.subscriptionSeen || !client.active || client.expiry <= now))
|
||||||
|
{
|
||||||
client = {};
|
client = {};
|
||||||
|
}
|
||||||
|
|
||||||
const bool changed = ElectOwner(now);
|
clientIndex = 0;
|
||||||
|
for (const Client& client : m_clients)
|
||||||
|
{
|
||||||
|
if (oldClientIDs[clientIndex] != client.clientID ||
|
||||||
|
wasSubscribed[clientIndex] != client.subscribed ||
|
||||||
|
wasOwnerCapable[clientIndex] != client.ownerCapable)
|
||||||
|
subscribersChanged = true;
|
||||||
|
++clientIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool changed = ElectOwner(now) || subscribersChanged;
|
||||||
ReleaseSRWLockExclusive(&m_lock);
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
if (changed)
|
if (changed)
|
||||||
WakePublisher();
|
WakePublisher();
|
||||||
@@ -251,7 +299,9 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID,
|
|||||||
client->active = false;
|
client->active = false;
|
||||||
client->expiry = 0;
|
client->expiry = 0;
|
||||||
client->immediate = false;
|
client->immediate = false;
|
||||||
wake = ElectOwner(now);
|
client->nextDelivery = 0;
|
||||||
|
wake = true;
|
||||||
|
wake |= ElectOwner(now);
|
||||||
}
|
}
|
||||||
ReleaseSRWLockExclusive(&m_lock);
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
if (wake)
|
if (wake)
|
||||||
@@ -285,12 +335,16 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wake = false;
|
const bool reset = client->generation != schedule.generation ||
|
||||||
|
(schedule.flags & KVMFR_FRAME_SCHEDULE_RESET);
|
||||||
if (client->generation != schedule.generation)
|
bool wake = reset || !client->active ||
|
||||||
|
client->period != schedule.period ||
|
||||||
|
client->targetSlack != schedule.targetSlack;
|
||||||
|
if (reset)
|
||||||
{
|
{
|
||||||
client->lastFeedbackFrameSerial = 0;
|
client->lastFeedbackFrameSerial = 0;
|
||||||
client->immediate = false;
|
client->immediate = false;
|
||||||
|
client->nextDelivery = now + schedule.period;
|
||||||
}
|
}
|
||||||
client->generation = schedule.generation;
|
client->generation = schedule.generation;
|
||||||
client->period = schedule.period;
|
client->period = schedule.period;
|
||||||
@@ -298,7 +352,10 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID,
|
|||||||
client->expiry = now + static_cast<uint64_t>(schedule.lease) * 1000000;
|
client->expiry = now + static_cast<uint64_t>(schedule.lease) * 1000000;
|
||||||
client->active = true;
|
client->active = true;
|
||||||
if (schedule.flags & KVMFR_FRAME_SCHEDULE_IMMEDIATE)
|
if (schedule.flags & KVMFR_FRAME_SCHEDULE_IMMEDIATE)
|
||||||
|
{
|
||||||
client->immediate = true;
|
client->immediate = true;
|
||||||
|
wake = true;
|
||||||
|
}
|
||||||
wake |= ElectOwner(now);
|
wake |= ElectOwner(now);
|
||||||
if (m_scheduling && client->clientID == m_schedule.clientID &&
|
if (m_scheduling && client->clientID == m_schedule.clientID &&
|
||||||
client->generation == m_schedule.generation && client->immediate)
|
client->generation == m_schedule.generation && client->immediate)
|
||||||
@@ -346,6 +403,7 @@ bool CFrameScheduler::ApplyFeedback(Client& client,
|
|||||||
}
|
}
|
||||||
m_lastPhaseError = schedule.phaseError;
|
m_lastPhaseError = schedule.phaseError;
|
||||||
client.lastFeedbackFrameSerial = schedule.feedbackFrameSerial;
|
client.lastFeedbackFrameSerial = schedule.feedbackFrameSerial;
|
||||||
|
client.nextDelivery = m_nextDeadline;
|
||||||
return correction != 0;
|
return correction != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,6 +417,23 @@ void CFrameScheduler::AdvanceDeadline(uint64_t now)
|
|||||||
m_nextDeadline += periods * m_schedule.period;
|
m_nextDeadline += periods * m_schedule.period;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CFrameScheduler::AdvanceDelivery(Client& client, uint64_t now)
|
||||||
|
{
|
||||||
|
if (!client.nextDelivery)
|
||||||
|
{
|
||||||
|
client.nextDelivery = now + client.period;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.nextDelivery += client.period;
|
||||||
|
if (client.nextDelivery <= now)
|
||||||
|
{
|
||||||
|
const uint64_t periods =
|
||||||
|
(now - client.nextDelivery) / client.period + 1;
|
||||||
|
client.nextDelivery += periods * client.period;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CFrameScheduler::GetSchedule(Schedule& schedule) const
|
bool CFrameScheduler::GetSchedule(Schedule& schedule) const
|
||||||
{
|
{
|
||||||
AcquireSRWLockShared(&m_lock);
|
AcquireSRWLockShared(&m_lock);
|
||||||
@@ -463,7 +538,11 @@ void CFrameScheduler::FramePublished(const Schedule& schedule,
|
|||||||
|
|
||||||
Client * client = FindClient(m_schedule.clientID);
|
Client * client = FindClient(m_schedule.clientID);
|
||||||
if (client)
|
if (client)
|
||||||
|
{
|
||||||
client->immediate = false;
|
client->immediate = false;
|
||||||
|
client->lastDeliveredFrameSerial = frameSerial;
|
||||||
|
client->deliveredFrameValid = true;
|
||||||
|
}
|
||||||
m_lastPublishedFrameSerial = frameSerial;
|
m_lastPublishedFrameSerial = frameSerial;
|
||||||
++m_publishedFrames;
|
++m_publishedFrames;
|
||||||
if (periodic)
|
if (periodic)
|
||||||
@@ -471,6 +550,8 @@ void CFrameScheduler::FramePublished(const Schedule& schedule,
|
|||||||
m_nextDeadline += m_schedule.period;
|
m_nextDeadline += m_schedule.period;
|
||||||
AdvanceDeadline(now);
|
AdvanceDeadline(now);
|
||||||
}
|
}
|
||||||
|
if (client)
|
||||||
|
client->nextDelivery = m_nextDeadline;
|
||||||
}
|
}
|
||||||
ReleaseSRWLockExclusive(&m_lock);
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
}
|
}
|
||||||
@@ -487,22 +568,134 @@ void CFrameScheduler::FrameRepublished(const Schedule& schedule,
|
|||||||
|
|
||||||
Client * client = FindClient(m_schedule.clientID);
|
Client * client = FindClient(m_schedule.clientID);
|
||||||
if (client)
|
if (client)
|
||||||
|
{
|
||||||
client->immediate = false;
|
client->immediate = false;
|
||||||
|
client->lastDeliveredFrameSerial = frameSerial;
|
||||||
|
client->deliveredFrameValid = true;
|
||||||
|
client->nextDelivery = m_nextDeadline;
|
||||||
|
}
|
||||||
m_lastPublishedFrameSerial = frameSerial;
|
m_lastPublishedFrameSerial = frameSerial;
|
||||||
++m_publishedFrames;
|
++m_publishedFrames;
|
||||||
}
|
}
|
||||||
ReleaseSRWLockExclusive(&m_lock);
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned CFrameScheduler::GetSecondaryRecipients(
|
||||||
|
const uint32_t * clientIDs, unsigned count, uint32_t frameSerial,
|
||||||
|
uint64_t now, uint32_t * recipients) const
|
||||||
|
{
|
||||||
|
AcquireSRWLockShared(&m_lock);
|
||||||
|
unsigned recipientCount = 0;
|
||||||
|
for (unsigned i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
if (m_scheduling && clientIDs[i] == m_schedule.clientID)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const Client * selected = nullptr;
|
||||||
|
for (const Client& client : m_clients)
|
||||||
|
if (client.clientID == clientIDs[i])
|
||||||
|
{
|
||||||
|
selected = &client;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool active = selected && selected->active &&
|
||||||
|
selected->expiry > now;
|
||||||
|
const bool sameFrame = selected && selected->deliveredFrameValid &&
|
||||||
|
selected->lastDeliveredFrameSerial == frameSerial;
|
||||||
|
bool due = !sameFrame;
|
||||||
|
if (active)
|
||||||
|
{
|
||||||
|
const uint64_t target = selected->nextDelivery >
|
||||||
|
selected->targetSlack ?
|
||||||
|
selected->nextDelivery - selected->targetSlack : 0;
|
||||||
|
due = selected->immediate ||
|
||||||
|
(!sameFrame && (!selected->nextDelivery || target <= now));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (due)
|
||||||
|
recipients[recipientCount++] = clientIDs[i];
|
||||||
|
}
|
||||||
|
ReleaseSRWLockShared(&m_lock);
|
||||||
|
return recipientCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFrameScheduler::GetSecondaryTarget(uint32_t frameSerial,
|
||||||
|
uint64_t now, const uint32_t * blockedClientIDs,
|
||||||
|
unsigned blockedCount, uint64_t& target) const
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
target = now;
|
||||||
|
|
||||||
|
AcquireSRWLockShared(&m_lock);
|
||||||
|
for (const Client& client : m_clients)
|
||||||
|
{
|
||||||
|
if (!client.clientID || !client.subscribed ||
|
||||||
|
(m_scheduling && client.clientID == m_schedule.clientID) ||
|
||||||
|
(client.deliveredFrameValid &&
|
||||||
|
client.lastDeliveredFrameSerial == frameSerial &&
|
||||||
|
!client.immediate))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool blocked = false;
|
||||||
|
for (unsigned i = 0; i < blockedCount; ++i)
|
||||||
|
if (blockedClientIDs[i] == client.clientID)
|
||||||
|
{
|
||||||
|
blocked = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (blocked)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint64_t candidate = now;
|
||||||
|
if (client.active && client.expiry > now && !client.immediate &&
|
||||||
|
client.nextDelivery > client.targetSlack)
|
||||||
|
candidate = client.nextDelivery - client.targetSlack;
|
||||||
|
if (candidate < now)
|
||||||
|
candidate = now;
|
||||||
|
|
||||||
|
if (!found || candidate < target)
|
||||||
|
{
|
||||||
|
target = candidate;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReleaseSRWLockShared(&m_lock);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
void CFrameScheduler::FrameDelivered(const uint32_t * clientIDs,
|
void CFrameScheduler::FrameDelivered(const uint32_t * clientIDs,
|
||||||
unsigned count)
|
unsigned count, uint32_t frameSerial, uint64_t now)
|
||||||
{
|
{
|
||||||
AcquireSRWLockExclusive(&m_lock);
|
AcquireSRWLockExclusive(&m_lock);
|
||||||
for (unsigned i = 0; i < count; ++i)
|
for (unsigned i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
Client * client = FindClient(clientIDs[i]);
|
Client * client = FindClient(clientIDs[i]);
|
||||||
if (client)
|
if (!client)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const bool immediate = client->immediate;
|
||||||
client->immediate = false;
|
client->immediate = false;
|
||||||
|
client->lastDeliveredFrameSerial = frameSerial;
|
||||||
|
client->deliveredFrameValid = true;
|
||||||
|
|
||||||
|
if (!client->active || client->expiry <= now)
|
||||||
|
{
|
||||||
|
client->nextDelivery = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_scheduling && client->clientID == m_schedule.clientID)
|
||||||
|
{
|
||||||
|
client->nextDelivery = m_nextDeadline;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool periodic = !client->nextDelivery ||
|
||||||
|
client->nextDelivery <= now ||
|
||||||
|
client->nextDelivery - now <= client->targetSlack;
|
||||||
|
if (!immediate || periodic)
|
||||||
|
AdvanceDelivery(*client, now);
|
||||||
}
|
}
|
||||||
ReleaseSRWLockExclusive(&m_lock);
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,11 +49,15 @@ private:
|
|||||||
uint64_t period;
|
uint64_t period;
|
||||||
uint64_t targetSlack;
|
uint64_t targetSlack;
|
||||||
uint64_t expiry;
|
uint64_t expiry;
|
||||||
|
uint64_t nextDelivery;
|
||||||
uint32_t lastFeedbackFrameSerial;
|
uint32_t lastFeedbackFrameSerial;
|
||||||
|
uint32_t lastDeliveredFrameSerial;
|
||||||
bool subscribed;
|
bool subscribed;
|
||||||
|
bool ownerCapable;
|
||||||
bool subscriptionSeen;
|
bool subscriptionSeen;
|
||||||
bool active;
|
bool active;
|
||||||
bool immediate;
|
bool immediate;
|
||||||
|
bool deliveredFrameValid;
|
||||||
};
|
};
|
||||||
|
|
||||||
mutable SRWLOCK m_lock = SRWLOCK_INIT;
|
mutable SRWLOCK m_lock = SRWLOCK_INIT;
|
||||||
@@ -85,6 +89,7 @@ private:
|
|||||||
bool ElectOwner(uint64_t now);
|
bool ElectOwner(uint64_t now);
|
||||||
bool ApplyFeedback(Client& client, const KVMFRFrameSchedule& schedule);
|
bool ApplyFeedback(Client& client, const KVMFRFrameSchedule& schedule);
|
||||||
void AdvanceDeadline(uint64_t now);
|
void AdvanceDeadline(uint64_t now);
|
||||||
|
static void AdvanceDelivery(Client& client, uint64_t now);
|
||||||
void WakePublisher() const;
|
void WakePublisher() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -95,7 +100,7 @@ public:
|
|||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
void UpdateSubscribers(const uint32_t * clientIDs, unsigned count,
|
void UpdateSubscribers(const uint32_t * clientIDs, unsigned count,
|
||||||
uint64_t now);
|
const uint32_t * ownerClientIDs, unsigned ownerCount, uint64_t now);
|
||||||
bool UpdateSchedule(uint32_t sourceClientID,
|
bool UpdateSchedule(uint32_t sourceClientID,
|
||||||
const KVMFRFrameSchedule& schedule, uint64_t now);
|
const KVMFRFrameSchedule& schedule, uint64_t now);
|
||||||
bool GetSchedule(Schedule& schedule) const;
|
bool GetSchedule(Schedule& schedule) const;
|
||||||
@@ -108,7 +113,15 @@ public:
|
|||||||
void FramePublished(const Schedule& schedule, uint32_t frameSerial,
|
void FramePublished(const Schedule& schedule, uint32_t frameSerial,
|
||||||
uint64_t now, bool periodic);
|
uint64_t now, bool periodic);
|
||||||
void FrameRepublished(const Schedule& schedule, uint32_t frameSerial);
|
void FrameRepublished(const Schedule& schedule, uint32_t frameSerial);
|
||||||
void FrameDelivered(const uint32_t * clientIDs, unsigned count);
|
unsigned GetSecondaryRecipients(const uint32_t * clientIDs,
|
||||||
|
unsigned count, uint32_t frameSerial, uint64_t now,
|
||||||
|
uint32_t * recipients) const;
|
||||||
|
bool GetSecondaryTarget(uint32_t frameSerial, uint64_t now,
|
||||||
|
const uint32_t * blockedClientIDs, unsigned blockedCount,
|
||||||
|
uint64_t& target) const;
|
||||||
|
void FrameDelivered(const uint32_t * clientIDs, unsigned count,
|
||||||
|
uint32_t frameSerial, uint64_t now);
|
||||||
|
void NotifyPublisher() const { WakePublisher(); }
|
||||||
void RecordFrameTiming(uint64_t duration);
|
void RecordFrameTiming(uint64_t duration);
|
||||||
void LogStatistics(uint64_t now);
|
void LogStatistics(uint64_t now);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1183,7 +1183,6 @@ bool CIndirectDeviceContext::SetupLGMP(size_t alignSize)
|
|||||||
|
|
||||||
m_maxFrameSize = maxFrameSize;
|
m_maxFrameSize = maxFrameSize;
|
||||||
m_publishedFrameIndex.store(-1, std::memory_order_release);
|
m_publishedFrameIndex.store(-1, std::memory_order_release);
|
||||||
m_frameResendPending = false;
|
|
||||||
m_framePublishSequence = 0;
|
m_framePublishSequence = 0;
|
||||||
memset(m_frameLastPublishSequence, 0,
|
memset(m_frameLastPublishSequence, 0,
|
||||||
sizeof(m_frameLastPublishSequence));
|
sizeof(m_frameLastPublishSequence));
|
||||||
@@ -1238,7 +1237,6 @@ void CIndirectDeviceContext::DeInitLGMP()
|
|||||||
{
|
{
|
||||||
m_frameScheduler.Reset();
|
m_frameScheduler.Reset();
|
||||||
m_publishedFrameIndex.store(-1, std::memory_order_release);
|
m_publishedFrameIndex.store(-1, std::memory_order_release);
|
||||||
m_frameResendPending = false;
|
|
||||||
m_framePublishSequence = 0;
|
m_framePublishSequence = 0;
|
||||||
memset(m_frameLastPublishSequence, 0,
|
memset(m_frameLastPublishSequence, 0,
|
||||||
sizeof(m_frameLastPublishSequence));
|
sizeof(m_frameLastPublishSequence));
|
||||||
@@ -1259,7 +1257,6 @@ void CIndirectDeviceContext::DeInitLGMP()
|
|||||||
|
|
||||||
AcquireSRWLockExclusive(&m_framePublishLock);
|
AcquireSRWLockExclusive(&m_framePublishLock);
|
||||||
m_publishedFrameIndex.store(-1, std::memory_order_release);
|
m_publishedFrameIndex.store(-1, std::memory_order_release);
|
||||||
m_frameResendPending = false;
|
|
||||||
m_framePublishSequence = 0;
|
m_framePublishSequence = 0;
|
||||||
memset(m_frameLastPublishSequence, 0,
|
memset(m_frameLastPublishSequence, 0,
|
||||||
sizeof(m_frameLastPublishSequence));
|
sizeof(m_frameLastPublishSequence));
|
||||||
@@ -1319,9 +1316,17 @@ void CIndirectDeviceContext::LGMPTimer()
|
|||||||
|
|
||||||
const uint64_t now = CFrameScheduler::Nanotime();
|
const uint64_t now = CFrameScheduler::Nanotime();
|
||||||
uint32_t clientIDs[LGMP_MAX_CLIENTS] = {};
|
uint32_t clientIDs[LGMP_MAX_CLIENTS] = {};
|
||||||
|
uint32_t ownerClientIDs[LGMP_MAX_CLIENTS] = {};
|
||||||
unsigned clientCount = 0;
|
unsigned clientCount = 0;
|
||||||
|
unsigned ownerClientCount = 0;
|
||||||
LGMP_STATUS subscriberStatus = lgmpHostGetClientIDs(
|
LGMP_STATUS subscriberStatus = lgmpHostGetClientIDs(
|
||||||
m_frameQueue, clientIDs, &clientCount);
|
m_frameQueue, clientIDs, &clientCount);
|
||||||
|
if (subscriberStatus == LGMP_OK)
|
||||||
|
{
|
||||||
|
memcpy(ownerClientIDs, clientIDs,
|
||||||
|
clientCount * sizeof(*ownerClientIDs));
|
||||||
|
ownerClientCount = clientCount;
|
||||||
|
}
|
||||||
for (unsigned queueIndex = 0;
|
for (unsigned queueIndex = 0;
|
||||||
subscriberStatus == LGMP_OK && queueIndex < LGMP_Q_FRAME_LEN;
|
subscriberStatus == LGMP_OK && queueIndex < LGMP_Q_FRAME_LEN;
|
||||||
++queueIndex)
|
++queueIndex)
|
||||||
@@ -1333,15 +1338,15 @@ void CIndirectDeviceContext::LGMPTimer()
|
|||||||
|
|
||||||
unsigned commonCount = 0;
|
unsigned commonCount = 0;
|
||||||
for (unsigned i = 0;
|
for (unsigned i = 0;
|
||||||
subscriberStatus == LGMP_OK && i < clientCount;
|
subscriberStatus == LGMP_OK && i < ownerClientCount;
|
||||||
++i)
|
++i)
|
||||||
for (unsigned candidate = 0; candidate < queueClientCount; ++candidate)
|
for (unsigned candidate = 0; candidate < queueClientCount; ++candidate)
|
||||||
if (clientIDs[i] == queueClientIDs[candidate])
|
if (ownerClientIDs[i] == queueClientIDs[candidate])
|
||||||
{
|
{
|
||||||
clientIDs[commonCount++] = clientIDs[i];
|
ownerClientIDs[commonCount++] = ownerClientIDs[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
clientCount = commonCount;
|
ownerClientCount = commonCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t data[LGMP_MSGS_SIZE];
|
uint8_t data[LGMP_MSGS_SIZE];
|
||||||
@@ -1376,21 +1381,6 @@ void CIndirectDeviceContext::LGMPTimer()
|
|||||||
sourceClientID, *frameSchedule, now);
|
sourceClientID, *frameSchedule, now);
|
||||||
if (!valid)
|
if (!valid)
|
||||||
DEBUG_WARN("Ignoring invalid KVMFR frame schedule");
|
DEBUG_WARN("Ignoring invalid KVMFR frame schedule");
|
||||||
else if ((frameSchedule->flags &
|
|
||||||
(KVMFR_FRAME_SCHEDULE_ACTIVE |
|
|
||||||
KVMFR_FRAME_SCHEDULE_IMMEDIATE)) ==
|
|
||||||
(KVMFR_FRAME_SCHEDULE_ACTIVE |
|
|
||||||
KVMFR_FRAME_SCHEDULE_IMMEDIATE))
|
|
||||||
{
|
|
||||||
CFrameScheduler::Schedule owner = {};
|
|
||||||
if (!m_frameScheduler.GetSchedule(owner) ||
|
|
||||||
owner.clientID != sourceClientID)
|
|
||||||
{
|
|
||||||
AcquireSRWLockExclusive(&m_framePublishLock);
|
|
||||||
m_frameResendPending = true;
|
|
||||||
ReleaseSRWLockExclusive(&m_framePublishLock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1399,7 +1389,9 @@ void CIndirectDeviceContext::LGMPTimer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (subscriberStatus == LGMP_OK)
|
if (subscriberStatus == LGMP_OK)
|
||||||
m_frameScheduler.UpdateSubscribers(clientIDs, clientCount, now);
|
m_frameScheduler.UpdateSubscribers(
|
||||||
|
clientIDs, clientCount,
|
||||||
|
ownerClientIDs, ownerClientCount, now);
|
||||||
else
|
else
|
||||||
DEBUG_WARN("Failed to query LGMP frame subscribers: %s",
|
DEBUG_WARN("Failed to query LGMP frame subscribers: %s",
|
||||||
lgmpStatusString(subscriberStatus));
|
lgmpStatusString(subscriberStatus));
|
||||||
@@ -1407,11 +1399,7 @@ void CIndirectDeviceContext::LGMPTimer()
|
|||||||
m_frameScheduler.LogStatistics(now);
|
m_frameScheduler.LogStatistics(now);
|
||||||
|
|
||||||
if (lgmpHostQueueNewSubs(m_frameQueue))
|
if (lgmpHostQueueNewSubs(m_frameQueue))
|
||||||
{
|
m_frameScheduler.NotifyPublisher();
|
||||||
AcquireSRWLockExclusive(&m_framePublishLock);
|
|
||||||
m_frameResendPending = true;
|
|
||||||
ReleaseSRWLockExclusive(&m_framePublishLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessFrameDeliveries();
|
ProcessFrameDeliveries();
|
||||||
|
|
||||||
@@ -1422,12 +1410,13 @@ void CIndirectDeviceContext::LGMPTimer()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CIndirectDeviceContext::PostSharedFrame(unsigned frameIndex,
|
CIndirectDeviceContext::SharedFramePostResult
|
||||||
uint32_t excludeClientID)
|
CIndirectDeviceContext::PostSharedFrame(unsigned frameIndex,
|
||||||
|
uint32_t excludeClientID, uint64_t now)
|
||||||
{
|
{
|
||||||
if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN ||
|
if (frameIndex >= LGMP_Q_FRAME_BUFFER_LEN ||
|
||||||
lgmpHostQueuePending(m_frameQueue) != 0)
|
lgmpHostQueuePending(m_frameQueue) != 0)
|
||||||
return false;
|
return SHARED_FRAME_FAILED;
|
||||||
|
|
||||||
uint32_t clientIDs[LGMP_MAX_CLIENTS] = {};
|
uint32_t clientIDs[LGMP_MAX_CLIENTS] = {};
|
||||||
unsigned clientCount = 0;
|
unsigned clientCount = 0;
|
||||||
@@ -1437,22 +1426,28 @@ bool CIndirectDeviceContext::PostSharedFrame(unsigned frameIndex,
|
|||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to query shared frame subscribers: %s",
|
DEBUG_ERROR("Failed to query shared frame subscribers: %s",
|
||||||
lgmpStatusString(status));
|
lgmpStatusString(status));
|
||||||
return false;
|
return SHARED_FRAME_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t recipients[LGMP_MAX_CLIENTS] = {};
|
||||||
|
const uint32_t frameSerial = m_frame[frameIndex]->frameSerial;
|
||||||
|
const unsigned recipientCount =
|
||||||
|
m_frameScheduler.GetSecondaryRecipients(
|
||||||
|
clientIDs, clientCount, frameSerial, now, recipients);
|
||||||
|
|
||||||
unsigned targetCount = 0;
|
unsigned targetCount = 0;
|
||||||
for (unsigned i = 0; i < clientCount; ++i)
|
for (unsigned i = 0; i < recipientCount; ++i)
|
||||||
{
|
{
|
||||||
bool excluded = clientIDs[i] == excludeClientID;
|
bool excluded = recipients[i] == excludeClientID;
|
||||||
for (const OwnerDelivery& delivery : m_ownerDelivery)
|
for (const OwnerDelivery& delivery : m_ownerDelivery)
|
||||||
if (delivery.active && delivery.clientID == clientIDs[i])
|
if (delivery.active && delivery.clientID == recipients[i])
|
||||||
{
|
{
|
||||||
excluded = true;
|
excluded = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!excluded)
|
if (!excluded)
|
||||||
clientIDs[targetCount++] = clientIDs[i];
|
recipients[targetCount++] = recipients[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!targetCount)
|
if (!targetCount)
|
||||||
@@ -1461,42 +1456,38 @@ bool CIndirectDeviceContext::PostSharedFrame(unsigned frameIndex,
|
|||||||
m_frameDelivery[frameIndex].sharedOwnerClientID = 0;
|
m_frameDelivery[frameIndex].sharedOwnerClientID = 0;
|
||||||
m_frameDelivery[frameIndex].sharedOwnerPending = false;
|
m_frameDelivery[frameIndex].sharedOwnerPending = false;
|
||||||
m_frameDelivery[frameIndex].sharedPending = false;
|
m_frameDelivery[frameIndex].sharedPending = false;
|
||||||
m_frameDelivery[frameIndex].sharedDelivered = true;
|
return SHARED_FRAME_IDLE;
|
||||||
m_frameResendPending = false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned recipientCount = 0;
|
unsigned postedCount = 0;
|
||||||
status = lgmpHostQueuePostForClients(
|
status = lgmpHostQueuePostForClients(
|
||||||
m_frameQueue, 0, m_frameMemory[frameIndex],
|
m_frameQueue, 0, m_frameMemory[frameIndex],
|
||||||
clientIDs, targetCount, &recipientCount);
|
recipients, targetCount, &postedCount);
|
||||||
if (status != LGMP_OK)
|
if (status != LGMP_OK)
|
||||||
{
|
{
|
||||||
if (status != LGMP_ERR_QUEUE_FULL)
|
if (status != LGMP_ERR_QUEUE_FULL)
|
||||||
DEBUG_ERROR("Failed to publish shared frame: %s",
|
DEBUG_ERROR("Failed to publish shared frame: %s",
|
||||||
lgmpStatusString(status));
|
lgmpStatusString(status));
|
||||||
return false;
|
return SHARED_FRAME_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!recipientCount)
|
if (!postedCount)
|
||||||
{
|
{
|
||||||
m_frameDelivery[frameIndex].sharedOwnerToken = 0;
|
m_frameDelivery[frameIndex].sharedOwnerToken = 0;
|
||||||
m_frameDelivery[frameIndex].sharedOwnerClientID = 0;
|
m_frameDelivery[frameIndex].sharedOwnerClientID = 0;
|
||||||
m_frameDelivery[frameIndex].sharedOwnerPending = false;
|
m_frameDelivery[frameIndex].sharedOwnerPending = false;
|
||||||
m_frameDelivery[frameIndex].sharedPending = false;
|
m_frameDelivery[frameIndex].sharedPending = false;
|
||||||
m_frameDelivery[frameIndex].sharedDelivered = true;
|
return SHARED_FRAME_IDLE;
|
||||||
m_frameResendPending = false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_frameDelivery[frameIndex].sharedOwnerToken = 0;
|
m_frameDelivery[frameIndex].sharedOwnerToken = 0;
|
||||||
m_frameDelivery[frameIndex].sharedOwnerClientID = 0;
|
m_frameDelivery[frameIndex].sharedOwnerClientID = 0;
|
||||||
m_frameDelivery[frameIndex].sharedOwnerPending = false;
|
m_frameDelivery[frameIndex].sharedOwnerPending = false;
|
||||||
m_frameDelivery[frameIndex].sharedPending = true;
|
m_frameDelivery[frameIndex].sharedPending = true;
|
||||||
m_frameDelivery[frameIndex].sharedDelivered = true;
|
if (postedCount == targetCount)
|
||||||
m_frameResendPending = false;
|
m_frameScheduler.FrameDelivered(
|
||||||
m_frameScheduler.FrameDelivered(clientIDs, targetCount);
|
recipients, targetCount, frameSerial, now);
|
||||||
return true;
|
return SHARED_FRAME_POSTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CIndirectDeviceContext::PostSharedOwnerFrame(unsigned frameIndex,
|
bool CIndirectDeviceContext::PostSharedOwnerFrame(unsigned frameIndex,
|
||||||
@@ -1523,8 +1514,6 @@ bool CIndirectDeviceContext::PostSharedOwnerFrame(unsigned frameIndex,
|
|||||||
delivery.sharedOwnerClientID = schedule.clientID;
|
delivery.sharedOwnerClientID = schedule.clientID;
|
||||||
delivery.sharedOwnerPending = true;
|
delivery.sharedOwnerPending = true;
|
||||||
delivery.sharedPending = true;
|
delivery.sharedPending = true;
|
||||||
if (!delivery.sharedDelivered)
|
|
||||||
m_frameResendPending = true;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1538,28 +1527,26 @@ void CIndirectDeviceContext::ProcessFrameDeliveries()
|
|||||||
|
|
||||||
AcquireSRWLockExclusive(&m_framePublishLock);
|
AcquireSRWLockExclusive(&m_framePublishLock);
|
||||||
|
|
||||||
|
bool released = false;
|
||||||
for (unsigned i = 0; i < LGMP_Q_FRAME_BUFFER_LEN; ++i)
|
for (unsigned i = 0; i < LGMP_Q_FRAME_BUFFER_LEN; ++i)
|
||||||
{
|
{
|
||||||
if (m_frameDelivery[i].sharedOwnerPending &&
|
if (m_frameDelivery[i].sharedOwnerPending &&
|
||||||
!lgmpHostQueueMessagePending(
|
!lgmpHostQueueMessagePending(
|
||||||
m_frameQueue, m_frameMemory[i],
|
m_frameQueue, m_frameMemory[i],
|
||||||
m_frameDelivery[i].sharedOwnerToken))
|
m_frameDelivery[i].sharedOwnerToken))
|
||||||
|
{
|
||||||
m_frameDelivery[i].sharedOwnerPending = false;
|
m_frameDelivery[i].sharedOwnerPending = false;
|
||||||
|
released = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_frameDelivery[i].sharedPending &&
|
if (m_frameDelivery[i].sharedPending &&
|
||||||
!lgmpHostQueuePayloadPending(m_frameQueue, m_frameMemory[i]))
|
!lgmpHostQueuePayloadPending(m_frameQueue, m_frameMemory[i]))
|
||||||
|
{
|
||||||
m_frameDelivery[i].sharedPending = false;
|
m_frameDelivery[i].sharedPending = false;
|
||||||
|
released = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CFrameScheduler::Schedule schedule = {};
|
|
||||||
const bool scheduled = m_frameScheduler.GetSchedule(schedule);
|
|
||||||
const uint64_t scheduleToken = scheduled ?
|
|
||||||
FrameScheduleToken(schedule) : 0;
|
|
||||||
const LONG publishedFrameIndex =
|
|
||||||
m_publishedFrameIndex.load(std::memory_order_acquire);
|
|
||||||
|
|
||||||
int newestAcked = -1;
|
|
||||||
uint32_t newestAckedClient = 0;
|
|
||||||
for (unsigned queueIndex = 0;
|
for (unsigned queueIndex = 0;
|
||||||
queueIndex < LGMP_Q_FRAME_LEN;
|
queueIndex < LGMP_Q_FRAME_LEN;
|
||||||
++queueIndex)
|
++queueIndex)
|
||||||
@@ -1572,91 +1559,15 @@ void CIndirectDeviceContext::ProcessFrameDeliveries()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
const unsigned frameIndex = owner.frameIndex;
|
const unsigned frameIndex = owner.frameIndex;
|
||||||
const bool latestDelivery =
|
|
||||||
static_cast<LONG>(frameIndex) == publishedFrameIndex &&
|
|
||||||
m_frameLastPublishSequence[frameIndex] == m_framePublishSequence;
|
|
||||||
const bool authoritative = (!scheduled && latestDelivery) ||
|
|
||||||
(scheduled && owner.clientID == schedule.clientID &&
|
|
||||||
owner.token == scheduleToken);
|
|
||||||
if (authoritative &&
|
|
||||||
(newestAcked < 0 ||
|
|
||||||
m_frameLastPublishSequence[frameIndex] >
|
|
||||||
m_frameLastPublishSequence[newestAcked]))
|
|
||||||
{
|
|
||||||
newestAcked = static_cast<int>(frameIndex);
|
|
||||||
newestAckedClient = owner.clientID;
|
|
||||||
}
|
|
||||||
else if (!authoritative && !latestDelivery)
|
|
||||||
m_frameResendPending = true;
|
|
||||||
|
|
||||||
m_frameDelivery[frameIndex].ownerQueueMask &=
|
m_frameDelivery[frameIndex].ownerQueueMask &=
|
||||||
~(1U << queueIndex);
|
~(1U << queueIndex);
|
||||||
owner = {};
|
owner = {};
|
||||||
}
|
released = true;
|
||||||
|
|
||||||
if (newestAcked >= 0)
|
|
||||||
{
|
|
||||||
FrameDelivery& delivery = m_frameDelivery[newestAcked];
|
|
||||||
const bool needsShared = !delivery.sharedDelivered;
|
|
||||||
|
|
||||||
const bool latest = newestAcked == publishedFrameIndex &&
|
|
||||||
m_frameLastPublishSequence[newestAcked] == m_framePublishSequence;
|
|
||||||
if (needsShared &&
|
|
||||||
(!latest ||
|
|
||||||
m_frameInFlight[newestAcked].load(std::memory_order_acquire) ||
|
|
||||||
lgmpHostQueuePending(m_frameQueue) != 0))
|
|
||||||
{
|
|
||||||
m_frameResendPending = true;
|
|
||||||
}
|
|
||||||
else if (needsShared &&
|
|
||||||
!PostSharedFrame(
|
|
||||||
static_cast<unsigned>(newestAcked), newestAckedClient))
|
|
||||||
{
|
|
||||||
m_frameResendPending = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_frameResendPending &&
|
|
||||||
lgmpHostQueuePending(m_frameQueue) == 0)
|
|
||||||
{
|
|
||||||
const LONG frameIndex =
|
|
||||||
m_publishedFrameIndex.load(std::memory_order_acquire);
|
|
||||||
if (frameIndex >= 0 &&
|
|
||||||
!m_frameDelivery[frameIndex].sharedPending &&
|
|
||||||
!m_frameInFlight[frameIndex].load(std::memory_order_acquire))
|
|
||||||
{
|
|
||||||
FrameDelivery& delivery = m_frameDelivery[frameIndex];
|
|
||||||
bool ownerDelivered = !scheduled;
|
|
||||||
if (scheduled)
|
|
||||||
{
|
|
||||||
ownerDelivered =
|
|
||||||
delivery.sharedOwnerClientID == schedule.clientID &&
|
|
||||||
delivery.sharedOwnerToken == scheduleToken;
|
|
||||||
for (const OwnerDelivery& owner : m_ownerDelivery)
|
|
||||||
if (owner.active &&
|
|
||||||
owner.clientID == schedule.clientID &&
|
|
||||||
owner.token == scheduleToken &&
|
|
||||||
owner.frameIndex == static_cast<unsigned>(frameIndex))
|
|
||||||
{
|
|
||||||
ownerDelivered = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool reserveSharedOwner = scheduled &&
|
|
||||||
delivery.sharedOwnerClientID == schedule.clientID &&
|
|
||||||
delivery.sharedOwnerToken == scheduleToken &&
|
|
||||||
FindAvailableOwnerQueue(static_cast<unsigned>(frameIndex)) < 0;
|
|
||||||
if (ownerDelivered && !reserveSharedOwner)
|
|
||||||
{
|
|
||||||
const uint32_t excludeClientID = scheduled ?
|
|
||||||
schedule.clientID : delivery.sharedOwnerClientID;
|
|
||||||
PostSharedFrame(
|
|
||||||
static_cast<unsigned>(frameIndex), excludeClientID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ReleaseSRWLockExclusive(&m_framePublishLock);
|
ReleaseSRWLockExclusive(&m_framePublishLock);
|
||||||
|
|
||||||
|
if (released)
|
||||||
|
m_frameScheduler.NotifyPublisher();
|
||||||
}
|
}
|
||||||
|
|
||||||
int CIndirectDeviceContext::FindAvailableOwnerQueue(
|
int CIndirectDeviceContext::FindAvailableOwnerQueue(
|
||||||
@@ -1781,6 +1692,60 @@ void CIndirectDeviceContext::ProcessFrameQueue()
|
|||||||
ProcessFrameDeliveries();
|
ProcessFrameDeliveries();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CIndirectDeviceContext::GetSharedFrameTarget(uint64_t now,
|
||||||
|
uint64_t& target)
|
||||||
|
{
|
||||||
|
if (!m_frameQueue)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
AcquireSRWLockShared(&m_framePublishLock);
|
||||||
|
const LONG frameIndex =
|
||||||
|
m_publishedFrameIndex.load(std::memory_order_acquire);
|
||||||
|
if (frameIndex < 0 ||
|
||||||
|
m_frameInFlight[frameIndex].load(std::memory_order_acquire) ||
|
||||||
|
lgmpHostQueuePending(m_frameQueue) != 0)
|
||||||
|
{
|
||||||
|
ReleaseSRWLockShared(&m_framePublishLock);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t blockedClientIDs[LGMP_Q_FRAME_LEN] = {};
|
||||||
|
unsigned blockedCount = 0;
|
||||||
|
for (const OwnerDelivery& delivery : m_ownerDelivery)
|
||||||
|
if (delivery.active)
|
||||||
|
blockedClientIDs[blockedCount++] = delivery.clientID;
|
||||||
|
|
||||||
|
const bool result = m_frameScheduler.GetSecondaryTarget(
|
||||||
|
m_frame[frameIndex]->frameSerial, now,
|
||||||
|
blockedClientIDs, blockedCount, target);
|
||||||
|
ReleaseSRWLockShared(&m_framePublishLock);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CIndirectDeviceContext::ReplaySharedFrame(uint64_t now, bool& retry)
|
||||||
|
{
|
||||||
|
retry = false;
|
||||||
|
if (!m_frameQueue)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
AcquireSRWLockExclusive(&m_framePublishLock);
|
||||||
|
const LONG frameIndex =
|
||||||
|
m_publishedFrameIndex.load(std::memory_order_acquire);
|
||||||
|
if (frameIndex < 0 ||
|
||||||
|
m_frameInFlight[frameIndex].load(std::memory_order_acquire) ||
|
||||||
|
lgmpHostQueuePending(m_frameQueue) != 0)
|
||||||
|
{
|
||||||
|
ReleaseSRWLockExclusive(&m_framePublishLock);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SharedFramePostResult result = PostSharedFrame(
|
||||||
|
static_cast<unsigned>(frameIndex), 0, now);
|
||||||
|
ReleaseSRWLockExclusive(&m_framePublishLock);
|
||||||
|
retry = result == SHARED_FRAME_FAILED;
|
||||||
|
return result == SHARED_FRAME_POSTED;
|
||||||
|
}
|
||||||
|
|
||||||
CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrameBuffer(
|
CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrameBuffer(
|
||||||
unsigned pitch, const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat,
|
unsigned pitch, const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat,
|
||||||
const RECT * dirtyRects, unsigned nbDirtyRects)
|
const RECT * dirtyRects, unsigned nbDirtyRects)
|
||||||
@@ -1950,6 +1915,7 @@ bool CIndirectDeviceContext::PublishFrameBuffer(unsigned frameIndex,
|
|||||||
if (!m_frameQueue || frameIndex >= LGMP_Q_FRAME_BUFFER_LEN)
|
if (!m_frameQueue || frameIndex >= LGMP_Q_FRAME_BUFFER_LEN)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
const uint64_t now = CFrameScheduler::Nanotime();
|
||||||
AcquireSRWLockExclusive(&m_framePublishLock);
|
AcquireSRWLockExclusive(&m_framePublishLock);
|
||||||
CFrameScheduler::Schedule currentSchedule = {};
|
CFrameScheduler::Schedule currentSchedule = {};
|
||||||
const bool scheduling =
|
const bool scheduling =
|
||||||
@@ -1991,17 +1957,15 @@ bool CIndirectDeviceContext::PublishFrameBuffer(unsigned frameIndex,
|
|||||||
|
|
||||||
FrameDelivery& delivery = m_frameDelivery[frameIndex];
|
FrameDelivery& delivery = m_frameDelivery[frameIndex];
|
||||||
delivery.ownerQueueMask |= 1U << queueIndex;
|
delivery.ownerQueueMask |= 1U << queueIndex;
|
||||||
delivery.sharedDelivered = false;
|
|
||||||
published = true;
|
published = true;
|
||||||
|
|
||||||
if (!PostSharedFrame(frameIndex, schedule.clientID))
|
PostSharedFrame(frameIndex, schedule.clientID, now);
|
||||||
m_frameResendPending = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
published = PostSharedFrame(frameIndex, 0);
|
published = PostSharedFrame(frameIndex, 0, now) != SHARED_FRAME_FAILED;
|
||||||
|
|
||||||
if (published)
|
if (published)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -111,10 +111,16 @@ private:
|
|||||||
std::atomic<LONG> m_publishedFrameIndex = -1;
|
std::atomic<LONG> m_publishedFrameIndex = -1;
|
||||||
std::atomic<bool> m_frameInFlight[LGMP_Q_FRAME_BUFFER_LEN] = {};
|
std::atomic<bool> m_frameInFlight[LGMP_Q_FRAME_BUFFER_LEN] = {};
|
||||||
SRWLOCK m_framePublishLock = SRWLOCK_INIT;
|
SRWLOCK m_framePublishLock = SRWLOCK_INIT;
|
||||||
bool m_frameResendPending = false;
|
|
||||||
uint64_t m_framePublishSequence = 0;
|
uint64_t m_framePublishSequence = 0;
|
||||||
uint64_t m_frameLastPublishSequence[LGMP_Q_FRAME_BUFFER_LEN] = {};
|
uint64_t m_frameLastPublishSequence[LGMP_Q_FRAME_BUFFER_LEN] = {};
|
||||||
|
|
||||||
|
enum SharedFramePostResult
|
||||||
|
{
|
||||||
|
SHARED_FRAME_FAILED,
|
||||||
|
SHARED_FRAME_IDLE,
|
||||||
|
SHARED_FRAME_POSTED,
|
||||||
|
};
|
||||||
|
|
||||||
struct FrameDelivery
|
struct FrameDelivery
|
||||||
{
|
{
|
||||||
uint64_t sharedOwnerToken = 0;
|
uint64_t sharedOwnerToken = 0;
|
||||||
@@ -122,7 +128,6 @@ private:
|
|||||||
uint32_t sharedOwnerClientID = 0;
|
uint32_t sharedOwnerClientID = 0;
|
||||||
bool sharedOwnerPending = false;
|
bool sharedOwnerPending = false;
|
||||||
bool sharedPending = false;
|
bool sharedPending = false;
|
||||||
bool sharedDelivered = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OwnerDelivery
|
struct OwnerDelivery
|
||||||
@@ -185,7 +190,8 @@ private:
|
|||||||
int FindOwnerDelivery(uint32_t clientID) const;
|
int FindOwnerDelivery(uint32_t clientID) const;
|
||||||
int FindSharedOwnerDelivery(uint32_t clientID) const;
|
int FindSharedOwnerDelivery(uint32_t clientID) const;
|
||||||
bool HasOwnerDelivery(uint32_t clientID) const;
|
bool HasOwnerDelivery(uint32_t clientID) const;
|
||||||
bool PostSharedFrame(unsigned frameIndex, uint32_t excludeClientID);
|
SharedFramePostResult PostSharedFrame(unsigned frameIndex,
|
||||||
|
uint32_t excludeClientID, uint64_t now);
|
||||||
bool PostSharedOwnerFrame(unsigned frameIndex,
|
bool PostSharedOwnerFrame(unsigned frameIndex,
|
||||||
const CFrameScheduler::Schedule& schedule);
|
const CFrameScheduler::Schedule& schedule);
|
||||||
void ResendCursor();
|
void ResendCursor();
|
||||||
@@ -264,6 +270,8 @@ public:
|
|||||||
return m_publishedFrameIndex.load(std::memory_order_acquire) >= 0;
|
return m_publishedFrameIndex.load(std::memory_order_acquire) >= 0;
|
||||||
}
|
}
|
||||||
void ProcessFrameQueue();
|
void ProcessFrameQueue();
|
||||||
|
bool GetSharedFrameTarget(uint64_t now, uint64_t& target);
|
||||||
|
bool ReplaySharedFrame(uint64_t now, bool& retry);
|
||||||
PreparedFrameBuffer PrepareFrameBuffer(unsigned pitch, const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat, const RECT * dirtyRects, unsigned nbDirtyRects);
|
PreparedFrameBuffer PrepareFrameBuffer(unsigned pitch, const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat, const RECT * dirtyRects, unsigned nbDirtyRects);
|
||||||
bool PublishFrameBuffer(unsigned frameIndex,
|
bool PublishFrameBuffer(unsigned frameIndex,
|
||||||
const CFrameScheduler::Schedule& schedule);
|
const CFrameScheduler::Schedule& schedule);
|
||||||
|
|||||||
@@ -231,11 +231,15 @@ void CSwapChainProcessor::PublisherThread()
|
|||||||
m_devContext->GetPublishTarget(
|
m_devContext->GetPublishTarget(
|
||||||
now, target, schedule, periodic, republish);
|
now, target, schedule, periodic, republish);
|
||||||
|
|
||||||
if (!HasReadyCandidate())
|
const bool ready = HasReadyCandidate();
|
||||||
{
|
if (!ready)
|
||||||
if (republish && m_devContext->HasPublishedFrame())
|
|
||||||
{
|
{
|
||||||
m_devContext->ProcessFrameQueue();
|
m_devContext->ProcessFrameQueue();
|
||||||
|
if (HasReadyCandidate())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (republish && m_devContext->HasPublishedFrame())
|
||||||
|
{
|
||||||
if (m_devContext->RepublishFrameBuffer(schedule))
|
if (m_devContext->RepublishFrameBuffer(schedule))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -247,6 +251,17 @@ void CSwapChainProcessor::PublisherThread()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint64_t replayNow = CFrameScheduler::Nanotime();
|
||||||
|
uint64_t replayTarget;
|
||||||
|
if (m_devContext->GetSharedFrameTarget(replayNow, replayTarget))
|
||||||
|
{
|
||||||
|
bool retry = false;
|
||||||
|
if (replayTarget <= replayNow)
|
||||||
|
{
|
||||||
|
if (m_devContext->ReplaySharedFrame(replayNow, retry))
|
||||||
|
continue;
|
||||||
|
if (!retry)
|
||||||
|
{
|
||||||
if (m_publishTimer.Get())
|
if (m_publishTimer.Get())
|
||||||
CancelWaitableTimer(m_publishTimer.Get());
|
CancelWaitableTimer(m_publishTimer.Get());
|
||||||
if (WaitForMultipleObjects(
|
if (WaitForMultipleObjects(
|
||||||
@@ -255,6 +270,54 @@ void CSwapChainProcessor::PublisherThread()
|
|||||||
break;
|
break;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t delay = replayTarget > replayNow ?
|
||||||
|
replayTarget - replayNow : PUBLISH_RETRY_NS;
|
||||||
|
ArmPublishTimer(m_publishTimer.Get(), delay);
|
||||||
|
if (WaitForMultipleObjects(
|
||||||
|
ARRAYSIZE(timerHandles), timerHandles, FALSE, INFINITE) ==
|
||||||
|
WAIT_OBJECT_0)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_publishTimer.Get())
|
||||||
|
CancelWaitableTimer(m_publishTimer.Get());
|
||||||
|
if (WaitForMultipleObjects(
|
||||||
|
ARRAYSIZE(idleHandles), idleHandles, FALSE, INFINITE) ==
|
||||||
|
WAIT_OBJECT_0)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t replayTarget;
|
||||||
|
if (m_devContext->GetSharedFrameTarget(now, replayTarget) &&
|
||||||
|
replayTarget < target)
|
||||||
|
{
|
||||||
|
if (replayTarget <= now)
|
||||||
|
{
|
||||||
|
m_devContext->ProcessFrameQueue();
|
||||||
|
bool retry = false;
|
||||||
|
if (m_devContext->ReplaySharedFrame(
|
||||||
|
CFrameScheduler::Nanotime(), retry))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (retry)
|
||||||
|
replayTarget = now + PUBLISH_RETRY_NS;
|
||||||
|
else
|
||||||
|
replayTarget = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t delay = replayTarget > now ?
|
||||||
|
replayTarget - now : PUBLISH_RETRY_NS;
|
||||||
|
ArmPublishTimer(m_publishTimer.Get(), delay);
|
||||||
|
if (WaitForMultipleObjects(
|
||||||
|
ARRAYSIZE(timerHandles), timerHandles, FALSE, INFINITE) ==
|
||||||
|
WAIT_OBJECT_0)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (target > now)
|
if (target > now)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user