1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-04 16:24:29 +01:00

[d3d11] Add functions to emit externally generated CS chunks

This commit is contained in:
Philip Rebohle 2024-09-29 14:36:10 +02:00 committed by Philip Rebohle
parent abd888a0bb
commit 438a08f87c
4 changed files with 58 additions and 3 deletions

View File

@ -886,6 +886,15 @@ namespace dxvk {
} }
void D3D11ImmediateContext::EmitCsChunkExternal(
DxvkCsChunkRef&& Chunk,
bool Synchronize) {
// Do not update the sequence number when emitting a chunk
// from an external source since that would break tracking
m_csThread.injectChunk(std::move(Chunk), Synchronize);
}
void D3D11ImmediateContext::EmitCsChunk(DxvkCsChunkRef&& chunk) { void D3D11ImmediateContext::EmitCsChunk(DxvkCsChunkRef&& chunk) {
m_csSeqNum = m_csThread.dispatchChunk(std::move(chunk)); m_csSeqNum = m_csThread.dispatchChunk(std::move(chunk));
} }

View File

@ -97,6 +97,10 @@ namespace dxvk {
return m_multithread.AcquireLock(); return m_multithread.AcquireLock();
} }
void EmitCsChunkExternal(
DxvkCsChunkRef&& Chunk,
bool Synchronize);
private: private:
DxvkCsThread m_csThread; DxvkCsThread m_csThread;

View File

@ -127,6 +127,22 @@ namespace dxvk {
} }
void DxvkCsThread::injectChunk(DxvkCsChunkRef&& chunk, bool synchronize) {
std::unique_lock<dxvk::mutex> lock(m_mutex);
uint64_t timeline = ++m_chunksInjectedCount;
m_chunksInjected.push_back(std::move(chunk));
m_condOnAdd.notify_one();
if (synchronize) {
m_condOnSync.wait(lock, [this, timeline] {
return m_chunksInjectedComplete.load() >= timeline;
});
}
}
void DxvkCsThread::synchronize(uint64_t seq) { void DxvkCsThread::synchronize(uint64_t seq) {
// Avoid locking if we know the sync is a no-op, may // Avoid locking if we know the sync is a no-op, may
// reduce overhead if this is being called frequently // reduce overhead if this is being called frequently
@ -163,14 +179,18 @@ namespace dxvk {
try { try {
while (!m_stopped.load()) { while (!m_stopped.load()) {
bool injected = false;
{ std::unique_lock<dxvk::mutex> lock(m_mutex); { std::unique_lock<dxvk::mutex> lock(m_mutex);
m_condOnAdd.wait(lock, [this] { m_condOnAdd.wait(lock, [this] {
return (!m_chunksQueued.empty()) return (!m_chunksQueued.empty())
|| (!m_chunksInjected.empty())
|| (m_stopped.load()); || (m_stopped.load());
}); });
std::swap(chunks, m_chunksQueued); injected = !m_chunksInjected.empty();
std::swap(chunks, injected ? m_chunksInjected : m_chunksQueued);
} }
for (auto& chunk : chunks) { for (auto& chunk : chunks) {
@ -182,7 +202,7 @@ namespace dxvk {
// will only ever be contested if synchronization is // will only ever be contested if synchronization is
// actually necessary. // actually necessary.
{ std::unique_lock<dxvk::mutex> lock(m_counterMutex); { std::unique_lock<dxvk::mutex> lock(m_counterMutex);
m_chunksExecuted += 1; (injected ? m_chunksInjectedComplete : m_chunksExecuted) += 1u;
m_condOnSync.notify_one(); m_condOnSync.notify_one();
} }

View File

@ -183,6 +183,11 @@ namespace dxvk {
return true; return true;
} }
template<typename T>
bool push(T&& command) {
return push(command);
}
/** /**
* \brief Adds a command with data to the chunk * \brief Adds a command with data to the chunk
* *
@ -399,6 +404,19 @@ namespace dxvk {
*/ */
uint64_t dispatchChunk(DxvkCsChunkRef&& chunk); uint64_t dispatchChunk(DxvkCsChunkRef&& chunk);
/**
* \brief Injects chunk into the command stream
*
* This is meant to be used when serialized execution is required
* from a thread other than the main thread recording rendering
* commands. The context can still be safely accessed, but chunks
* will not be executed in any particular oder. These chunks also
* do not contribute to the main timeline.
* \param [in] chunk The chunk to dispatch
* \param [in] synchronize Whether to wait for execution to complete
*/
void injectChunk(DxvkCsChunkRef&& chunk, bool synchronize);
/** /**
* \brief Synchronizes with the thread * \brief Synchronizes with the thread
* *
@ -429,11 +447,15 @@ namespace dxvk {
std::atomic<uint64_t> m_chunksDispatched = { 0ull }; std::atomic<uint64_t> m_chunksDispatched = { 0ull };
std::atomic<uint64_t> m_chunksExecuted = { 0ull }; std::atomic<uint64_t> m_chunksExecuted = { 0ull };
std::atomic<uint64_t> m_chunksInjectedCount = { 0ull };
std::atomic<uint64_t> m_chunksInjectedComplete = { 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::vector<DxvkCsChunkRef> m_chunksQueued; std::vector<DxvkCsChunkRef> m_chunksQueued;
std::vector<DxvkCsChunkRef> m_chunksInjected;
dxvk::thread m_thread; dxvk::thread m_thread;
void threadFunc(); void threadFunc();