mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-13 16:08:50 +01:00
[dxvk] Introduce sequence numbers for CS submissions
This commit is contained in:
parent
bc137fdf37
commit
37f3d9208b
@ -548,8 +548,7 @@ namespace dxvk {
|
|||||||
// recorded prior to this function will be run
|
// recorded prior to this function will be run
|
||||||
FlushCsChunk();
|
FlushCsChunk();
|
||||||
|
|
||||||
if (m_csThread.isBusy())
|
m_csThread.synchronize(DxvkCsThread::SynchronizeAll);
|
||||||
m_csThread.synchronize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4759,8 +4759,7 @@ namespace dxvk {
|
|||||||
// recorded prior to this function will be run
|
// recorded prior to this function will be run
|
||||||
FlushCsChunk();
|
FlushCsChunk();
|
||||||
|
|
||||||
if (m_csThread.isBusy())
|
m_csThread.synchronize(DxvkCsThread::SynchronizeAll);
|
||||||
m_csThread.synchronize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -111,22 +111,32 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkCsThread::dispatchChunk(DxvkCsChunkRef&& chunk) {
|
uint64_t DxvkCsThread::dispatchChunk(DxvkCsChunkRef&& chunk) {
|
||||||
|
uint64_t seq;
|
||||||
|
|
||||||
{ std::unique_lock<dxvk::mutex> lock(m_mutex);
|
{ std::unique_lock<dxvk::mutex> lock(m_mutex);
|
||||||
|
seq = ++m_chunksDispatched;
|
||||||
m_chunksQueued.push(std::move(chunk));
|
m_chunksQueued.push(std::move(chunk));
|
||||||
m_chunksPending += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_condOnAdd.notify_one();
|
m_condOnAdd.notify_one();
|
||||||
|
return seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkCsThread::synchronize() {
|
void DxvkCsThread::synchronize(uint64_t seq) {
|
||||||
std::unique_lock<dxvk::mutex> lock(m_mutex);
|
// Avoid locking if we know the sync is a no-op, may
|
||||||
|
// reduce overhead if this is being called frequently
|
||||||
m_condOnSync.wait(lock, [this] {
|
if (seq > m_chunksExecuted.load(std::memory_order_acquire)) {
|
||||||
return !m_chunksPending.load();
|
std::unique_lock<dxvk::mutex> lock(m_mutex);
|
||||||
});
|
|
||||||
|
if (seq == SynchronizeAll)
|
||||||
|
seq = m_chunksDispatched.load();
|
||||||
|
|
||||||
|
m_condOnSync.wait(lock, [this, seq] {
|
||||||
|
return m_chunksExecuted.load() >= seq;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -139,8 +149,8 @@ namespace dxvk {
|
|||||||
while (!m_stopped.load()) {
|
while (!m_stopped.load()) {
|
||||||
{ std::unique_lock<dxvk::mutex> lock(m_mutex);
|
{ std::unique_lock<dxvk::mutex> lock(m_mutex);
|
||||||
if (chunk) {
|
if (chunk) {
|
||||||
if (--m_chunksPending == 0)
|
m_chunksExecuted++;
|
||||||
m_condOnSync.notify_one();
|
m_condOnSync.notify_one();
|
||||||
|
|
||||||
chunk = DxvkCsChunkRef();
|
chunk = DxvkCsChunkRef();
|
||||||
}
|
}
|
||||||
|
@ -379,7 +379,9 @@ namespace dxvk {
|
|||||||
class DxvkCsThread {
|
class DxvkCsThread {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
constexpr static uint64_t SynchronizeAll = ~0ull;
|
||||||
|
|
||||||
DxvkCsThread(const Rc<DxvkContext>& context);
|
DxvkCsThread(const Rc<DxvkContext>& context);
|
||||||
~DxvkCsThread();
|
~DxvkCsThread();
|
||||||
|
|
||||||
@ -389,41 +391,43 @@ namespace dxvk {
|
|||||||
* Can be used to efficiently play back large
|
* Can be used to efficiently play back large
|
||||||
* command lists recorded on another thread.
|
* command lists recorded on another thread.
|
||||||
* \param [in] chunk The chunk to dispatch
|
* \param [in] chunk The chunk to dispatch
|
||||||
|
* \returns Sequence number of the submission
|
||||||
*/
|
*/
|
||||||
void dispatchChunk(DxvkCsChunkRef&& chunk);
|
uint64_t dispatchChunk(DxvkCsChunkRef&& chunk);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Synchronizes with the thread
|
* \brief Synchronizes with the thread
|
||||||
*
|
*
|
||||||
* This waits for all chunks in the dispatch
|
* This waits for all chunks in the dispatch queue to
|
||||||
* queue to be processed by the thread. Note
|
* be processed by the thread, up to the given sequence
|
||||||
* that this does \e not implicitly call
|
* number. If the sequence number is 0, this will wait
|
||||||
* \ref flush.
|
* for all pending chunks to complete execution.
|
||||||
|
* \param [in] seq Sequence number to wait for.
|
||||||
*/
|
*/
|
||||||
void synchronize();
|
void synchronize(uint64_t seq);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Checks whether the worker thread is busy
|
* \brief Retrieves last executed sequence number
|
||||||
*
|
*
|
||||||
* Note that this information is only reliable if
|
* Can be used to avoid synchronization in some cases.
|
||||||
* only the calling thread dispatches jobs to the
|
* \returns Sequence number of last executed chunk
|
||||||
* worker queue and if the result is \c false.
|
|
||||||
* \returns \c true if there is still work to do
|
|
||||||
*/
|
*/
|
||||||
bool isBusy() const {
|
uint64_t lastSequenceNumber() const {
|
||||||
return m_chunksPending.load() != 0;
|
return m_chunksExecuted.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const Rc<DxvkContext> m_context;
|
const Rc<DxvkContext> m_context;
|
||||||
|
|
||||||
|
std::atomic<uint64_t> m_chunksDispatched = { 0ull };
|
||||||
|
std::atomic<uint64_t> m_chunksExecuted = { 0ull };
|
||||||
|
|
||||||
std::atomic<bool> m_stopped = { false };
|
std::atomic<bool> m_stopped = { false };
|
||||||
dxvk::mutex m_mutex;
|
dxvk::mutex m_mutex;
|
||||||
dxvk::condition_variable m_condOnAdd;
|
dxvk::condition_variable m_condOnAdd;
|
||||||
dxvk::condition_variable m_condOnSync;
|
dxvk::condition_variable m_condOnSync;
|
||||||
std::queue<DxvkCsChunkRef> m_chunksQueued;
|
std::queue<DxvkCsChunkRef> m_chunksQueued;
|
||||||
std::atomic<uint32_t> m_chunksPending = { 0u };
|
|
||||||
dxvk::thread m_thread;
|
dxvk::thread m_thread;
|
||||||
|
|
||||||
void threadFunc();
|
void threadFunc();
|
||||||
|
Loading…
Reference in New Issue
Block a user