mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 07:01:30 +00:00
308 lines
7.8 KiB
C++
308 lines
7.8 KiB
C++
/**
|
|
* Looking Glass
|
|
* Copyright © 2017-2026 The Looking Glass Authors
|
|
* https://looking-glass.io
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "transport/CFrameHub.h"
|
|
|
|
bool CFrameHub::Bind(
|
|
BackendId backend, uint32_t epoch, IFrameSink& sink)
|
|
{
|
|
if (!backend || !epoch)
|
|
return false;
|
|
|
|
CSRWExclusiveLock lock(m_lock);
|
|
if (m_sink)
|
|
return false;
|
|
m_sink = &sink;
|
|
m_backend = backend;
|
|
m_epoch = epoch;
|
|
m_slots.clear();
|
|
return true;
|
|
}
|
|
|
|
void CFrameHub::Unbind(BackendId backend, uint32_t epoch)
|
|
{
|
|
CSRWExclusiveLock lock(m_lock);
|
|
if (m_backend != backend || m_epoch != epoch)
|
|
return;
|
|
m_sink = nullptr;
|
|
m_backend = 0;
|
|
m_epoch = 0;
|
|
m_slots.clear();
|
|
}
|
|
|
|
bool CFrameHub::Valid(const FrameToken& token) const
|
|
{
|
|
return m_sink && token.sink == m_backend && token.epoch == m_epoch &&
|
|
token.slot < m_slots.size() && token.serial &&
|
|
m_slots[token.slot].serial == token.serial;
|
|
}
|
|
|
|
void CFrameHub::Invalidate(const FrameToken& token)
|
|
{
|
|
if (Valid(token))
|
|
m_slots[token.slot] = {};
|
|
}
|
|
|
|
size_t CFrameHub::GetMaxFrameSize() const
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
return m_sink ? m_sink->GetMaxFrameSize() : 0;
|
|
}
|
|
|
|
bool CFrameHub::FrameBufferAvailable(
|
|
const CFrameScheduler::Schedule& schedule, bool allowReadyReplacement)
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
return m_sink &&
|
|
m_sink->FrameBufferAvailable(schedule, allowReadyReplacement);
|
|
}
|
|
|
|
bool CFrameHub::HasPublishedFrame() const
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
return m_sink && m_sink->HasPublishedFrame();
|
|
}
|
|
|
|
void CFrameHub::ProcessDeliveries()
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
if (m_sink)
|
|
m_sink->ProcessDeliveries();
|
|
}
|
|
|
|
bool CFrameHub::GetPendingDeliveryTarget(uint64_t now, uint64_t& target)
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
return m_sink && m_sink->GetPendingDeliveryTarget(now, target);
|
|
}
|
|
|
|
bool CFrameHub::RetryPendingDelivery(uint64_t now, bool& retry)
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
return m_sink && m_sink->RetryPendingDelivery(now, retry);
|
|
}
|
|
|
|
PreparedFrameBuffer CFrameHub::PrepareFrameBuffer(unsigned pitch,
|
|
const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat,
|
|
const RECT * dirtyRects, unsigned nbDirtyRects,
|
|
const CFrameScheduler::Schedule& schedule, bool allowReadyReplacement)
|
|
{
|
|
PreparedFrameBuffer result = {};
|
|
CSRWExclusiveLock lock(m_lock);
|
|
if (!m_sink)
|
|
return result;
|
|
|
|
const SinkTarget target = m_sink->PrepareFrameBuffer(
|
|
pitch, srcFormat, dstFormat, dirtyRects, nbDirtyRects, schedule,
|
|
allowReadyReplacement);
|
|
if (!target.mem || target.slot >= MAX_SLOTS)
|
|
{
|
|
if (target.mem)
|
|
m_sink->AbortFrameBuffer(target.slot);
|
|
return result;
|
|
}
|
|
|
|
if (target.slot >= m_slots.size())
|
|
m_slots.resize(target.slot + 1);
|
|
if (++m_nextSerial == 0)
|
|
++m_nextSerial;
|
|
m_slots[target.slot].serial = m_nextSerial;
|
|
|
|
result.token.sink = m_backend;
|
|
result.token.epoch = m_epoch;
|
|
result.token.slot = target.slot;
|
|
result.token.serial = m_nextSerial;
|
|
result.resourceSlot = target.slot;
|
|
result.mem = target.mem;
|
|
result.heapOffset = target.heapOffset;
|
|
result.fullCopy = target.fullCopy;
|
|
return result;
|
|
}
|
|
|
|
bool CFrameHub::PublishFrameBuffer(const FrameToken& token,
|
|
const CFrameScheduler::Schedule& schedule, bool& deliveredToOwner)
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
return Valid(token) &&
|
|
m_sink->PublishFrameBuffer(token.slot, schedule, deliveredToOwner);
|
|
}
|
|
|
|
bool CFrameHub::RepublishFrameBuffer(
|
|
const CFrameScheduler::Schedule& schedule)
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
return m_sink && m_sink->RepublishFrameBuffer(schedule);
|
|
}
|
|
|
|
bool CFrameHub::TryFrameSubmitted(const FrameToken& token,
|
|
const CFrameScheduler::Schedule& schedule)
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
return Valid(token) &&
|
|
m_sink->TryFrameSubmitted(token.slot, schedule);
|
|
}
|
|
|
|
void CFrameHub::CommitFrameBuffer(const FrameToken& token,
|
|
const CFrameScheduler::Schedule& schedule, bool periodic,
|
|
bool deliveredToOwner)
|
|
{
|
|
CSRWExclusiveLock lock(m_lock);
|
|
if (Valid(token))
|
|
{
|
|
m_sink->CommitFrameBuffer(
|
|
token.slot, schedule, periodic, deliveredToOwner);
|
|
Slot& slot = m_slots[token.slot];
|
|
slot.committed = true;
|
|
if (slot.completionPending)
|
|
{
|
|
m_sink->CompleteFrameBuffer(
|
|
token.slot, slot.completionSucceeded);
|
|
Invalidate(token);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CFrameHub::AbortFrameBuffer(const FrameToken& token)
|
|
{
|
|
CSRWExclusiveLock lock(m_lock);
|
|
if (Valid(token))
|
|
{
|
|
m_sink->AbortFrameBuffer(token.slot);
|
|
Invalidate(token);
|
|
}
|
|
}
|
|
|
|
void CFrameHub::FailFrameBuffer(const FrameToken& token)
|
|
{
|
|
CSRWExclusiveLock lock(m_lock);
|
|
if (Valid(token))
|
|
{
|
|
m_sink->FailFrameBuffer(token.slot);
|
|
Invalidate(token);
|
|
}
|
|
}
|
|
|
|
void CFrameHub::CompleteFrameBuffer(
|
|
const FrameToken& token, bool succeeded)
|
|
{
|
|
CSRWExclusiveLock lock(m_lock);
|
|
if (Valid(token))
|
|
{
|
|
Slot& slot = m_slots[token.slot];
|
|
if (slot.committed)
|
|
{
|
|
m_sink->CompleteFrameBuffer(token.slot, succeeded);
|
|
Invalidate(token);
|
|
}
|
|
else
|
|
{
|
|
slot.completionPending = true;
|
|
slot.completionSucceeded = succeeded;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CFrameHub::SetFrameTiming(const FrameToken& token,
|
|
uint64_t captureTime, uint64_t postProcessTime, uint64_t copyTime,
|
|
uint64_t readyTime, uint64_t holdTime,
|
|
const CFrameScheduler::Schedule& schedule, uint64_t completedAt)
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
if (Valid(token))
|
|
m_sink->SetFrameTiming(token.slot, captureTime, postProcessTime,
|
|
copyTime, readyTime, holdTime, schedule, completedAt);
|
|
}
|
|
|
|
void CFrameHub::WriteFrameBuffer(const FrameToken& token, void * src,
|
|
size_t offset, size_t len, bool setWritePos) const
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
if (Valid(token))
|
|
m_sink->WriteFrameBuffer(
|
|
token.slot, src, offset, len, setWritePos);
|
|
}
|
|
|
|
void CFrameHub::WriteFrameBufferRows(const FrameToken& token, void * src,
|
|
size_t offset, size_t rowBytes, size_t pitch, unsigned rows) const
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
if (Valid(token))
|
|
m_sink->WriteFrameBufferRows(
|
|
token.slot, src, offset, rowBytes, pitch, rows);
|
|
}
|
|
|
|
void CFrameHub::FinalizeFrameBuffer(const FrameToken& token) const
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
if (Valid(token))
|
|
m_sink->FinalizeFrameBuffer(token.slot);
|
|
}
|
|
|
|
void CFrameHub::ObserveFrame(uint64_t now)
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
if (m_sink)
|
|
m_sink->ObserveFrame(now);
|
|
}
|
|
|
|
void CFrameHub::ForceFrame()
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
if (m_sink)
|
|
m_sink->ForceFrame();
|
|
}
|
|
|
|
bool CFrameHub::GetPublishTarget(uint64_t now, uint64_t& target,
|
|
CFrameScheduler::Schedule& schedule, bool& periodic, bool& republish)
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
return m_sink && m_sink->GetPublishTarget(
|
|
now, target, schedule, periodic, republish);
|
|
}
|
|
|
|
void CFrameHub::FrameMissed(const CFrameScheduler::Schedule& schedule,
|
|
uint64_t now, bool periodic)
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
if (m_sink)
|
|
m_sink->FrameMissed(schedule, now, periodic);
|
|
}
|
|
|
|
void CFrameHub::FrameSuperseded()
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
if (m_sink)
|
|
m_sink->FrameSuperseded();
|
|
}
|
|
|
|
HANDLE CFrameHub::GetFrameScheduleEvent() const
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
return m_sink ? m_sink->GetFrameScheduleEvent() : nullptr;
|
|
}
|
|
|
|
void CFrameHub::TryRecordFrameTiming(
|
|
const FrameToken& token, uint64_t duration)
|
|
{
|
|
CSRWSharedLock lock(m_lock);
|
|
if (Valid(token))
|
|
m_sink->TryRecordFrameTiming(duration);
|
|
}
|