mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 08:41:31 +00:00
[idd] scheduler: retain frames for publication deadlines
Prepare each acquired content frame into one of two private GPU candidates so the IddCx frame can be released without copying it to IVSHMEM immediately. Wake a high-resolution publisher at the client deadline and send the newest completed candidate. Preserve accumulated damage across superseded candidates, include the scheduling hold in end-to-end timing, and keep transport work on the existing physical copy queue.
This commit is contained in:
@@ -43,6 +43,7 @@ class CFrameBufferResource
|
|||||||
unsigned m_timingEffectIndex = 0;
|
unsigned m_timingEffectIndex = 0;
|
||||||
uint64_t m_timingToken = 0;
|
uint64_t m_timingToken = 0;
|
||||||
bool m_fullCopy = false;
|
bool m_fullCopy = false;
|
||||||
|
unsigned m_candidateIndex = 0;
|
||||||
ComPtr<ID3D12Resource> m_res;
|
ComPtr<ID3D12Resource> m_res;
|
||||||
void * m_map = nullptr;
|
void * m_map = nullptr;
|
||||||
|
|
||||||
@@ -75,6 +76,8 @@ class CFrameBufferResource
|
|||||||
unsigned GetTimingEffectIndex() const { return m_timingEffectIndex; }
|
unsigned GetTimingEffectIndex() const { return m_timingEffectIndex; }
|
||||||
uint64_t GetTimingToken () const { return m_timingToken; }
|
uint64_t GetTimingToken () const { return m_timingToken; }
|
||||||
bool IsFullCopy () const { return m_fullCopy; }
|
bool IsFullCopy () const { return m_fullCopy; }
|
||||||
|
void SetCandidateIndex(unsigned index) { m_candidateIndex = index; }
|
||||||
|
unsigned GetCandidateIndex() const { return m_candidateIndex; }
|
||||||
|
|
||||||
ComPtr<ID3D12Resource> Get() { return m_res; }
|
ComPtr<ID3D12Resource> Get() { return m_res; }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,6 +30,23 @@ static const uint64_t MIN_SAFETY_NS = 250000ULL;
|
|||||||
static const uint64_t LOG_INTERVAL_NS = 5000000000ULL;
|
static const uint64_t LOG_INTERVAL_NS = 5000000000ULL;
|
||||||
static const uint64_t CADENCE_BREAK = 4;
|
static const uint64_t CADENCE_BREAK = 4;
|
||||||
|
|
||||||
|
CFrameScheduler::CFrameScheduler()
|
||||||
|
{
|
||||||
|
m_wakeEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFrameScheduler::~CFrameScheduler()
|
||||||
|
{
|
||||||
|
if (m_wakeEvent)
|
||||||
|
CloseHandle(m_wakeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFrameScheduler::WakePublisher() const
|
||||||
|
{
|
||||||
|
if (m_wakeEvent)
|
||||||
|
SetEvent(m_wakeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t CFrameScheduler::Nanotime()
|
uint64_t CFrameScheduler::Nanotime()
|
||||||
{
|
{
|
||||||
static const uint64_t frequency = []()
|
static const uint64_t frequency = []()
|
||||||
@@ -58,7 +75,7 @@ CFrameScheduler::Client * CFrameScheduler::FindClient(uint32_t clientID)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrameScheduler::ElectOwner(uint64_t now)
|
bool CFrameScheduler::ElectOwner(uint64_t now)
|
||||||
{
|
{
|
||||||
Client * fastest = nullptr;
|
Client * fastest = nullptr;
|
||||||
Client * incumbent = FindClient(m_schedule.clientID);
|
Client * incumbent = FindClient(m_schedule.clientID);
|
||||||
@@ -91,6 +108,8 @@ void CFrameScheduler::ElectOwner(uint64_t now)
|
|||||||
|
|
||||||
const uint32_t oldClientID = m_schedule.clientID;
|
const uint32_t oldClientID = m_schedule.clientID;
|
||||||
const uint32_t oldGeneration = m_schedule.generation;
|
const uint32_t oldGeneration = m_schedule.generation;
|
||||||
|
const uint64_t oldPeriod = m_schedule.period;
|
||||||
|
const uint64_t oldSlack = m_schedule.targetSlack;
|
||||||
if (!fastest)
|
if (!fastest)
|
||||||
{
|
{
|
||||||
m_schedule = {};
|
m_schedule = {};
|
||||||
@@ -125,6 +144,9 @@ void CFrameScheduler::ElectOwner(uint64_t now)
|
|||||||
else if (ownerChanged && oldClientID)
|
else if (ownerChanged && oldClientID)
|
||||||
DEBUG_INFO("Frame timing owner released; using push delivery");
|
DEBUG_INFO("Frame timing owner released; using push delivery");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ownerChanged || oldGeneration != m_schedule.generation ||
|
||||||
|
oldPeriod != m_schedule.period || oldSlack != m_schedule.targetSlack;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrameScheduler::Reset()
|
void CFrameScheduler::Reset()
|
||||||
@@ -138,11 +160,8 @@ void CFrameScheduler::Reset()
|
|||||||
|
|
||||||
m_lastArrival = 0;
|
m_lastArrival = 0;
|
||||||
m_guestPeriod = 0;
|
m_guestPeriod = 0;
|
||||||
m_guestJitter = 0;
|
|
||||||
m_workEstimate = 0;
|
m_workEstimate = 0;
|
||||||
m_nextDeadline = 0;
|
m_nextDeadline = 0;
|
||||||
m_arrivalSamples = 0;
|
|
||||||
m_timingSamples = 0;
|
|
||||||
|
|
||||||
m_lastPublishedFrameSerial = 0;
|
m_lastPublishedFrameSerial = 0;
|
||||||
|
|
||||||
@@ -155,6 +174,7 @@ void CFrameScheduler::Reset()
|
|||||||
m_lastLogSkipped = 0;
|
m_lastLogSkipped = 0;
|
||||||
m_lastLogPublished = 0;
|
m_lastLogPublished = 0;
|
||||||
ReleaseSRWLockExclusive(&m_lock);
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
|
WakePublisher();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrameScheduler::UpdateSubscribers(const uint32_t * clientIDs,
|
void CFrameScheduler::UpdateSubscribers(const uint32_t * clientIDs,
|
||||||
@@ -185,8 +205,10 @@ void CFrameScheduler::UpdateSubscribers(const uint32_t * clientIDs,
|
|||||||
if (client.clientID && !client.subscribed)
|
if (client.clientID && !client.subscribed)
|
||||||
client = {};
|
client = {};
|
||||||
|
|
||||||
ElectOwner(now);
|
const bool changed = ElectOwner(now);
|
||||||
ReleaseSRWLockExclusive(&m_lock);
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
|
if (changed)
|
||||||
|
WakePublisher();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CFrameScheduler::UpdateSchedule(const KVMFRFrameSchedule& schedule,
|
bool CFrameScheduler::UpdateSchedule(const KVMFRFrameSchedule& schedule,
|
||||||
@@ -203,6 +225,7 @@ bool CFrameScheduler::UpdateSchedule(const KVMFRFrameSchedule& schedule,
|
|||||||
|
|
||||||
AcquireSRWLockExclusive(&m_lock);
|
AcquireSRWLockExclusive(&m_lock);
|
||||||
Client * client = FindClient(schedule.clientID);
|
Client * client = FindClient(schedule.clientID);
|
||||||
|
bool wake = false;
|
||||||
|
|
||||||
if (schedule.flags & KVMFR_FRAME_SCHEDULE_RELEASE)
|
if (schedule.flags & KVMFR_FRAME_SCHEDULE_RELEASE)
|
||||||
{
|
{
|
||||||
@@ -210,9 +233,11 @@ bool CFrameScheduler::UpdateSchedule(const KVMFRFrameSchedule& schedule,
|
|||||||
{
|
{
|
||||||
client->active = false;
|
client->active = false;
|
||||||
client->expiry = 0;
|
client->expiry = 0;
|
||||||
ElectOwner(now);
|
wake = ElectOwner(now);
|
||||||
}
|
}
|
||||||
ReleaseSRWLockExclusive(&m_lock);
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
|
if (wake)
|
||||||
|
WakePublisher();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,14 +267,19 @@ bool CFrameScheduler::UpdateSchedule(const KVMFRFrameSchedule& schedule,
|
|||||||
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)
|
||||||
|
{
|
||||||
m_forceNext = true;
|
m_forceNext = true;
|
||||||
ElectOwner(now);
|
wake = true;
|
||||||
ApplyFeedback(*client, schedule);
|
}
|
||||||
|
wake |= ElectOwner(now);
|
||||||
|
wake |= ApplyFeedback(*client, schedule);
|
||||||
ReleaseSRWLockExclusive(&m_lock);
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
|
if (wake)
|
||||||
|
WakePublisher();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrameScheduler::ApplyFeedback(Client& client,
|
bool CFrameScheduler::ApplyFeedback(Client& client,
|
||||||
const KVMFRFrameSchedule& schedule)
|
const KVMFRFrameSchedule& schedule)
|
||||||
{
|
{
|
||||||
if (!m_scheduling || client.clientID != m_schedule.clientID ||
|
if (!m_scheduling || client.clientID != m_schedule.clientID ||
|
||||||
@@ -261,7 +291,7 @@ void CFrameScheduler::ApplyFeedback(Client& client,
|
|||||||
!m_lastPublishedFrameSerial ||
|
!m_lastPublishedFrameSerial ||
|
||||||
static_cast<int32_t>(schedule.feedbackFrameSerial -
|
static_cast<int32_t>(schedule.feedbackFrameSerial -
|
||||||
m_lastPublishedFrameSerial) > 0)
|
m_lastPublishedFrameSerial) > 0)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
int64_t correction = schedule.phaseError / 4;
|
int64_t correction = schedule.phaseError / 4;
|
||||||
const int64_t limit = static_cast<int64_t>(m_schedule.period / 4);
|
const int64_t limit = static_cast<int64_t>(m_schedule.period / 4);
|
||||||
@@ -280,6 +310,7 @@ void CFrameScheduler::ApplyFeedback(Client& client,
|
|||||||
}
|
}
|
||||||
m_lastPhaseError = schedule.phaseError;
|
m_lastPhaseError = schedule.phaseError;
|
||||||
client.lastFeedbackFrameSerial = schedule.feedbackFrameSerial;
|
client.lastFeedbackFrameSerial = schedule.feedbackFrameSerial;
|
||||||
|
return correction != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrameScheduler::AdvanceDeadline(uint64_t now)
|
void CFrameScheduler::AdvanceDeadline(uint64_t now)
|
||||||
@@ -311,35 +342,35 @@ void CFrameScheduler::ObserveFrame(uint64_t now)
|
|||||||
const uint64_t interval = now - m_lastArrival;
|
const uint64_t interval = now - m_lastArrival;
|
||||||
if (m_guestPeriod && interval > m_guestPeriod * CADENCE_BREAK)
|
if (m_guestPeriod && interval > m_guestPeriod * CADENCE_BREAK)
|
||||||
{
|
{
|
||||||
m_guestPeriod = 0;
|
m_guestPeriod = 0;
|
||||||
m_guestJitter = 0;
|
m_forceNext = true;
|
||||||
m_arrivalSamples = 0;
|
|
||||||
m_forceNext = true;
|
|
||||||
}
|
}
|
||||||
else if (interval >= MIN_PERIOD_NS && interval <= MAX_PERIOD_NS)
|
else if (interval >= MIN_PERIOD_NS && interval <= MAX_PERIOD_NS)
|
||||||
{
|
{
|
||||||
if (!m_guestPeriod)
|
if (!m_guestPeriod)
|
||||||
m_guestPeriod = interval;
|
m_guestPeriod = interval;
|
||||||
else
|
else
|
||||||
{
|
|
||||||
const uint64_t error = m_guestPeriod > interval ?
|
|
||||||
m_guestPeriod - interval : interval - m_guestPeriod;
|
|
||||||
m_guestPeriod = (m_guestPeriod * 7 + interval) / 8;
|
m_guestPeriod = (m_guestPeriod * 7 + interval) / 8;
|
||||||
m_guestJitter = (m_guestJitter * 7 + error) / 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_arrivalSamples < 32)
|
|
||||||
++m_arrivalSamples;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_lastArrival = now;
|
m_lastArrival = now;
|
||||||
ReleaseSRWLockExclusive(&m_lock);
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CFrameScheduler::SelectFrame(uint64_t now, bool force,
|
void CFrameScheduler::ForceFrame()
|
||||||
uint32_t& generation)
|
|
||||||
{
|
{
|
||||||
|
AcquireSRWLockExclusive(&m_lock);
|
||||||
|
m_forceNext = true;
|
||||||
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
|
WakePublisher();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFrameScheduler::GetPublishTarget(uint64_t now, uint64_t& target,
|
||||||
|
uint32_t& generation, bool& periodic)
|
||||||
|
{
|
||||||
|
target = now;
|
||||||
generation = 0;
|
generation = 0;
|
||||||
|
periodic = false;
|
||||||
AcquireSRWLockExclusive(&m_lock);
|
AcquireSRWLockExclusive(&m_lock);
|
||||||
if (!m_scheduling)
|
if (!m_scheduling)
|
||||||
{
|
{
|
||||||
@@ -348,31 +379,41 @@ bool CFrameScheduler::SelectFrame(uint64_t now, bool force,
|
|||||||
}
|
}
|
||||||
|
|
||||||
generation = m_schedule.generation;
|
generation = m_schedule.generation;
|
||||||
AdvanceDeadline(now);
|
|
||||||
|
|
||||||
if (force)
|
if (m_forceNext)
|
||||||
m_forceNext = true;
|
{
|
||||||
|
periodic = m_nextDeadline <= now;
|
||||||
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_forceNext || m_arrivalSamples < 4 || m_timingSamples < 4)
|
periodic = true;
|
||||||
|
if (m_nextDeadline <= now)
|
||||||
{
|
{
|
||||||
ReleaseSRWLockExclusive(&m_lock);
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint64_t safety =
|
const uint64_t safety =
|
||||||
max(MIN_SAFETY_NS,
|
max(MIN_SAFETY_NS, m_workEstimate / 8);
|
||||||
max(m_guestJitter * 2, m_workEstimate / 8));
|
const uint64_t lead =
|
||||||
const uint64_t nextArrival = m_lastArrival + m_guestPeriod;
|
m_schedule.targetSlack + m_workEstimate + safety;
|
||||||
const bool process = nextArrival <= now ||
|
target = m_nextDeadline > lead ? m_nextDeadline - lead : now;
|
||||||
nextArrival + m_workEstimate + safety > m_nextDeadline;
|
if (target < now)
|
||||||
if (!process)
|
target = now;
|
||||||
++m_skippedFrames;
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFrameScheduler::FrameSuperseded()
|
||||||
|
{
|
||||||
|
AcquireSRWLockExclusive(&m_lock);
|
||||||
|
++m_skippedFrames;
|
||||||
ReleaseSRWLockExclusive(&m_lock);
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
return process;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrameScheduler::FramePublished(uint32_t generation,
|
void CFrameScheduler::FramePublished(uint32_t generation,
|
||||||
uint32_t frameSerial, uint64_t now)
|
uint32_t frameSerial, uint64_t now, bool periodic)
|
||||||
{
|
{
|
||||||
AcquireSRWLockExclusive(&m_lock);
|
AcquireSRWLockExclusive(&m_lock);
|
||||||
if (m_scheduling && generation == m_schedule.generation)
|
if (m_scheduling && generation == m_schedule.generation)
|
||||||
@@ -380,8 +421,11 @@ void CFrameScheduler::FramePublished(uint32_t generation,
|
|||||||
m_forceNext = false;
|
m_forceNext = false;
|
||||||
m_lastPublishedFrameSerial = frameSerial;
|
m_lastPublishedFrameSerial = frameSerial;
|
||||||
++m_publishedFrames;
|
++m_publishedFrames;
|
||||||
m_nextDeadline += m_schedule.period;
|
if (periodic)
|
||||||
AdvanceDeadline(now);
|
{
|
||||||
|
m_nextDeadline += m_schedule.period;
|
||||||
|
AdvanceDeadline(now);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ReleaseSRWLockExclusive(&m_lock);
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
}
|
}
|
||||||
@@ -428,7 +472,5 @@ void CFrameScheduler::RecordFrameTiming(uint64_t duration)
|
|||||||
else
|
else
|
||||||
m_workEstimate = (m_workEstimate * 31 + duration) / 32;
|
m_workEstimate = (m_workEstimate * 31 + duration) / 32;
|
||||||
|
|
||||||
if (m_timingSamples < 32)
|
|
||||||
++m_timingSamples;
|
|
||||||
ReleaseSRWLockExclusive(&m_lock);
|
ReleaseSRWLockExclusive(&m_lock);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
mutable SRWLOCK m_lock = SRWLOCK_INIT;
|
mutable SRWLOCK m_lock = SRWLOCK_INIT;
|
||||||
|
HANDLE m_wakeEvent = nullptr;
|
||||||
Client m_clients[LGMP_MAX_CLIENTS] = {};
|
Client m_clients[LGMP_MAX_CLIENTS] = {};
|
||||||
Schedule m_schedule = {};
|
Schedule m_schedule = {};
|
||||||
bool m_scheduling = false;
|
bool m_scheduling = false;
|
||||||
@@ -61,11 +62,8 @@ private:
|
|||||||
|
|
||||||
uint64_t m_lastArrival = 0;
|
uint64_t m_lastArrival = 0;
|
||||||
uint64_t m_guestPeriod = 0;
|
uint64_t m_guestPeriod = 0;
|
||||||
uint64_t m_guestJitter = 0;
|
|
||||||
uint64_t m_workEstimate = 0;
|
uint64_t m_workEstimate = 0;
|
||||||
uint64_t m_nextDeadline = 0;
|
uint64_t m_nextDeadline = 0;
|
||||||
unsigned m_arrivalSamples = 0;
|
|
||||||
unsigned m_timingSamples = 0;
|
|
||||||
|
|
||||||
uint32_t m_lastPublishedFrameSerial = 0;
|
uint32_t m_lastPublishedFrameSerial = 0;
|
||||||
|
|
||||||
@@ -79,11 +77,15 @@ private:
|
|||||||
uint64_t m_lastLogPublished = 0;
|
uint64_t m_lastLogPublished = 0;
|
||||||
|
|
||||||
Client * FindClient(uint32_t clientID);
|
Client * FindClient(uint32_t clientID);
|
||||||
void ElectOwner(uint64_t now);
|
bool ElectOwner(uint64_t now);
|
||||||
void ApplyFeedback(Client& client, const KVMFRFrameSchedule& schedule);
|
bool ApplyFeedback(Client& client, const KVMFRFrameSchedule& schedule);
|
||||||
void AdvanceDeadline(uint64_t now);
|
void AdvanceDeadline(uint64_t now);
|
||||||
|
void WakePublisher() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
CFrameScheduler();
|
||||||
|
~CFrameScheduler();
|
||||||
|
|
||||||
static uint64_t Nanotime();
|
static uint64_t Nanotime();
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
@@ -91,10 +93,14 @@ public:
|
|||||||
uint64_t now);
|
uint64_t now);
|
||||||
bool UpdateSchedule(const KVMFRFrameSchedule& schedule, uint64_t now);
|
bool UpdateSchedule(const KVMFRFrameSchedule& schedule, uint64_t now);
|
||||||
bool GetSchedule(Schedule& schedule) const;
|
bool GetSchedule(Schedule& schedule) const;
|
||||||
|
HANDLE GetWakeEvent() const { return m_wakeEvent; }
|
||||||
void ObserveFrame(uint64_t now);
|
void ObserveFrame(uint64_t now);
|
||||||
bool SelectFrame(uint64_t now, bool force, uint32_t& generation);
|
void ForceFrame();
|
||||||
|
bool GetPublishTarget(uint64_t now, uint64_t& target,
|
||||||
|
uint32_t& generation, bool& periodic);
|
||||||
|
void FrameSuperseded();
|
||||||
void FramePublished(uint32_t generation, uint32_t frameSerial,
|
void FramePublished(uint32_t generation, uint32_t frameSerial,
|
||||||
uint64_t now);
|
uint64_t now, bool periodic);
|
||||||
void RecordFrameTiming(uint64_t duration);
|
void RecordFrameTiming(uint64_t duration);
|
||||||
void LogStatistics(uint64_t now);
|
void LogStatistics(uint64_t now);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1246,7 +1246,10 @@ void CIndirectDeviceContext::LGMPTimer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
LGMP_STATUS status;
|
LGMP_STATUS status;
|
||||||
if ((status = lgmpHostProcess(m_lgmp)) != LGMP_OK)
|
AcquireSRWLockExclusive(&m_lgmpProcessLock);
|
||||||
|
status = lgmpHostProcess(m_lgmp);
|
||||||
|
ReleaseSRWLockExclusive(&m_lgmpProcessLock);
|
||||||
|
if (status != LGMP_OK)
|
||||||
{
|
{
|
||||||
if (status == LGMP_ERR_CORRUPTED)
|
if (status == LGMP_ERR_CORRUPTED)
|
||||||
{
|
{
|
||||||
@@ -1348,6 +1351,19 @@ bool CIndirectDeviceContext::FrameBufferAvailable() const
|
|||||||
return !m_frameInFlight[frameIndex].load(std::memory_order_acquire);
|
return !m_frameInFlight[frameIndex].load(std::memory_order_acquire);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CIndirectDeviceContext::ProcessFrameQueue()
|
||||||
|
{
|
||||||
|
if (!m_lgmp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AcquireSRWLockExclusive(&m_lgmpProcessLock);
|
||||||
|
const LGMP_STATUS status = lgmpHostProcess(m_lgmp);
|
||||||
|
ReleaseSRWLockExclusive(&m_lgmpProcessLock);
|
||||||
|
|
||||||
|
if (status != LGMP_OK && status != LGMP_ERR_CORRUPTED)
|
||||||
|
DEBUG_ERROR("lgmpHostProcess Failed: %s", lgmpStatusString(status));
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
@@ -1524,11 +1540,6 @@ bool CIndirectDeviceContext::PublishFrameBuffer(unsigned frameIndex,
|
|||||||
}
|
}
|
||||||
ReleaseSRWLockExclusive(&m_framePublishLock);
|
ReleaseSRWLockExclusive(&m_framePublishLock);
|
||||||
|
|
||||||
if (status == LGMP_OK)
|
|
||||||
m_frameScheduler.FramePublished(
|
|
||||||
scheduleGeneration, m_frame[frameIndex]->frameSerial,
|
|
||||||
CFrameScheduler::Nanotime());
|
|
||||||
|
|
||||||
if (status != LGMP_OK)
|
if (status != LGMP_OK)
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to publish frame: %s", lgmpStatusString(status));
|
DEBUG_ERROR("Failed to publish frame: %s", lgmpStatusString(status));
|
||||||
@@ -1538,15 +1549,37 @@ bool CIndirectDeviceContext::PublishFrameBuffer(unsigned frameIndex,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CIndirectDeviceContext::CommitFrameBuffer(unsigned frameIndex,
|
||||||
|
uint32_t scheduleGeneration, bool periodic)
|
||||||
|
{
|
||||||
|
if (frameIndex >= LGMP_Q_FRAME_LEN)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_frameScheduler.FramePublished(
|
||||||
|
scheduleGeneration, m_frame[frameIndex]->frameSerial,
|
||||||
|
CFrameScheduler::Nanotime(), periodic);
|
||||||
|
}
|
||||||
|
|
||||||
void CIndirectDeviceContext::ObserveFrame(uint64_t now)
|
void CIndirectDeviceContext::ObserveFrame(uint64_t now)
|
||||||
{
|
{
|
||||||
m_frameScheduler.ObserveFrame(now);
|
m_frameScheduler.ObserveFrame(now);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CIndirectDeviceContext::SelectFrame(uint64_t now, bool force,
|
void CIndirectDeviceContext::ForceFrame()
|
||||||
uint32_t& generation)
|
|
||||||
{
|
{
|
||||||
return m_frameScheduler.SelectFrame(now, force, generation);
|
m_frameScheduler.ForceFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CIndirectDeviceContext::GetPublishTarget(uint64_t now,
|
||||||
|
uint64_t& target, uint32_t& generation, bool& periodic)
|
||||||
|
{
|
||||||
|
return m_frameScheduler.GetPublishTarget(
|
||||||
|
now, target, generation, periodic);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIndirectDeviceContext::FrameSuperseded()
|
||||||
|
{
|
||||||
|
m_frameScheduler.FrameSuperseded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIndirectDeviceContext::RecordFrameTiming(uint64_t duration)
|
void CIndirectDeviceContext::RecordFrameTiming(uint64_t duration)
|
||||||
|
|||||||
@@ -86,9 +86,10 @@ private:
|
|||||||
|
|
||||||
CIVSHMEM m_ivshmem;
|
CIVSHMEM m_ivshmem;
|
||||||
|
|
||||||
PLGMPHost m_lgmp = nullptr;
|
PLGMPHost m_lgmp = nullptr;
|
||||||
WDFTIMER m_lgmpTimer = nullptr;
|
WDFTIMER m_lgmpTimer = nullptr;
|
||||||
PLGMPHostQueue m_frameQueue = nullptr;
|
PLGMPHostQueue m_frameQueue = nullptr;
|
||||||
|
SRWLOCK m_lgmpProcessLock = SRWLOCK_INIT;
|
||||||
|
|
||||||
CFrameScheduler m_frameScheduler;
|
CFrameScheduler m_frameScheduler;
|
||||||
|
|
||||||
@@ -224,8 +225,11 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool FrameBufferAvailable() const;
|
bool FrameBufferAvailable() const;
|
||||||
|
void ProcessFrameQueue();
|
||||||
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, uint32_t scheduleGeneration);
|
bool PublishFrameBuffer(unsigned frameIndex, uint32_t scheduleGeneration);
|
||||||
|
void CommitFrameBuffer(unsigned frameIndex, uint32_t scheduleGeneration,
|
||||||
|
bool periodic);
|
||||||
void AbortFrameBuffer(unsigned frameIndex);
|
void AbortFrameBuffer(unsigned frameIndex);
|
||||||
void FailFrameBuffer(unsigned frameIndex);
|
void FailFrameBuffer(unsigned frameIndex);
|
||||||
void CompleteFrameBuffer(unsigned frameIndex);
|
void CompleteFrameBuffer(unsigned frameIndex);
|
||||||
@@ -235,7 +239,14 @@ public:
|
|||||||
void FinalizeFrameBuffer(unsigned frameIndex) const;
|
void FinalizeFrameBuffer(unsigned frameIndex) const;
|
||||||
|
|
||||||
void ObserveFrame(uint64_t now);
|
void ObserveFrame(uint64_t now);
|
||||||
bool SelectFrame(uint64_t now, bool force, uint32_t& generation);
|
void ForceFrame();
|
||||||
|
bool GetPublishTarget(uint64_t now, uint64_t& target,
|
||||||
|
uint32_t& generation, bool& periodic);
|
||||||
|
void FrameSuperseded();
|
||||||
|
HANDLE GetFrameScheduleEvent() const
|
||||||
|
{
|
||||||
|
return m_frameScheduler.GetWakeEvent();
|
||||||
|
}
|
||||||
void RecordFrameTiming(uint64_t duration);
|
void RecordFrameTiming(uint64_t duration);
|
||||||
|
|
||||||
void SendCursor(const IDARG_OUT_QUERY_HWCURSOR & info, const BYTE * data,
|
void SendCursor(const IDARG_OUT_QUERY_HWCURSOR & info, const BYTE * data,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -55,8 +55,50 @@ private:
|
|||||||
CFrameBufferPool m_fbPool;
|
CFrameBufferPool m_fbPool;
|
||||||
CPostProcessor m_postProcessors[LGMP_Q_FRAME_LEN];
|
CPostProcessor m_postProcessors[LGMP_Q_FRAME_LEN];
|
||||||
|
|
||||||
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_thread[2];
|
enum CandidateState
|
||||||
|
{
|
||||||
|
CANDIDATE_FREE,
|
||||||
|
CANDIDATE_PREPARING,
|
||||||
|
CANDIDATE_READY,
|
||||||
|
CANDIDATE_PUBLISHING,
|
||||||
|
CANDIDATE_HELD,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FrameCandidate
|
||||||
|
{
|
||||||
|
CandidateState state = CANDIDATE_FREE;
|
||||||
|
ComPtr<ID3D12Resource> resource;
|
||||||
|
D12FrameFormat srcFormat = {};
|
||||||
|
D12FrameFormat dstFormat = {};
|
||||||
|
RECT dirtyRects[LG_MAX_DIRTY_RECTS] = {};
|
||||||
|
unsigned nbDirtyRects = 0;
|
||||||
|
unsigned pitch = 0;
|
||||||
|
size_t frameSize = 0;
|
||||||
|
uint64_t sequence = 0;
|
||||||
|
uint64_t damageGeneration = 0;
|
||||||
|
uint64_t captureTime = 0;
|
||||||
|
uint64_t postProcessStart = 0;
|
||||||
|
uint64_t prepareCopyStart = 0;
|
||||||
|
uint64_t prepareReady = 0;
|
||||||
|
uint64_t prepareGPUStart = 0;
|
||||||
|
uint64_t prepareGPUEnd = 0;
|
||||||
|
unsigned timingEffectIndex = 0;
|
||||||
|
uint64_t timingToken = 0;
|
||||||
|
bool prepareTimingValid = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
FrameCandidate m_candidates[LGMP_Q_FRAME_LEN];
|
||||||
|
SRWLOCK m_candidateLock = SRWLOCK_INIT;
|
||||||
|
SRWLOCK m_damageLock = SRWLOCK_INIT;
|
||||||
|
SRWLOCK m_pipelineLock = SRWLOCK_INIT;
|
||||||
|
uint64_t m_candidateSequence = 0;
|
||||||
|
uint64_t m_damageGeneration = 0;
|
||||||
|
|
||||||
|
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_thread[3];
|
||||||
Wrappers::Event m_terminateEvent;
|
Wrappers::Event m_terminateEvent;
|
||||||
|
Wrappers::Event m_candidateEvent;
|
||||||
|
Wrappers::Event m_candidateAvailableEvent;
|
||||||
|
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_publishTimer;
|
||||||
|
|
||||||
Wrappers::Event m_cursorDataEvent;
|
Wrappers::Event m_cursorDataEvent;
|
||||||
BYTE* m_shapeBuffer;
|
BYTE* m_shapeBuffer;
|
||||||
@@ -89,12 +131,26 @@ private:
|
|||||||
void SwapChainThread();
|
void SwapChainThread();
|
||||||
bool SwapChainThreadCore();
|
bool SwapChainThreadCore();
|
||||||
|
|
||||||
|
static DWORD CALLBACK _PublisherThread(LPVOID arg);
|
||||||
|
void PublisherThread();
|
||||||
|
bool PublishNewestCandidate(
|
||||||
|
uint32_t scheduleGeneration, bool periodic, uint64_t publishStart);
|
||||||
|
bool HasReadyCandidate();
|
||||||
|
int AcquireCandidate();
|
||||||
|
void ReleaseCandidate(unsigned candidateIndex);
|
||||||
|
bool EnsureCandidateResource(unsigned candidateIndex,
|
||||||
|
ID3D12Resource * source);
|
||||||
|
void ResetCandidates();
|
||||||
|
void SignalCandidateState();
|
||||||
|
|
||||||
static DWORD CALLBACK _CursorThread(LPVOID arg);
|
static DWORD CALLBACK _CursorThread(LPVOID arg);
|
||||||
bool QueryHWCursor();
|
bool QueryHWCursor();
|
||||||
void CursorThread();
|
void CursorThread();
|
||||||
|
|
||||||
static void CompletionFunction(
|
static void CompletionFunction(
|
||||||
CD3D12CommandSlot * slot, bool result, void * param1, void * param2);
|
CD3D12CommandSlot * slot, bool result, void * param1, void * param2);
|
||||||
|
static void CandidateCompletionFunction(
|
||||||
|
CD3D12CommandSlot * slot, bool result, void * param1, void * param2);
|
||||||
void AccumulateFrameDamage(const RECT * dirtyRects, unsigned nbDirtyRects);
|
void AccumulateFrameDamage(const RECT * dirtyRects, unsigned nbDirtyRects);
|
||||||
void SetFullPendingDamage();
|
void SetFullPendingDamage();
|
||||||
#ifdef HAS_IDDCX_110
|
#ifdef HAS_IDDCX_110
|
||||||
|
|||||||
Reference in New Issue
Block a user