1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-03 22:24:13 +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) {
m_csSeqNum = m_csThread.dispatchChunk(std::move(chunk));
}

View File

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

View File

@ -125,6 +125,22 @@ namespace dxvk {
m_condOnAdd.notify_one();
return seq;
}
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) {
@ -163,14 +179,18 @@ namespace dxvk {
try {
while (!m_stopped.load()) {
bool injected = false;
{ std::unique_lock<dxvk::mutex> lock(m_mutex);
m_condOnAdd.wait(lock, [this] {
return (!m_chunksQueued.empty())
|| (!m_chunksInjected.empty())
|| (m_stopped.load());
});
std::swap(chunks, m_chunksQueued);
injected = !m_chunksInjected.empty();
std::swap(chunks, injected ? m_chunksInjected : m_chunksQueued);
}
for (auto& chunk : chunks) {
@ -182,7 +202,7 @@ namespace dxvk {
// will only ever be contested if synchronization is
// actually necessary.
{ std::unique_lock<dxvk::mutex> lock(m_counterMutex);
m_chunksExecuted += 1;
(injected ? m_chunksInjectedComplete : m_chunksExecuted) += 1u;
m_condOnSync.notify_one();
}

View File

@ -183,6 +183,11 @@ namespace dxvk {
return true;
}
template<typename T>
bool push(T&& command) {
return push(command);
}
/**
* \brief Adds a command with data to the chunk
*
@ -398,7 +403,20 @@ namespace dxvk {
* \returns Sequence number of the submission
*/
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
*
@ -428,12 +446,16 @@ namespace dxvk {
dxvk::mutex m_counterMutex;
std::atomic<uint64_t> m_chunksDispatched = { 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 };
dxvk::mutex m_mutex;
dxvk::condition_variable m_condOnAdd;
dxvk::condition_variable m_condOnSync;
std::vector<DxvkCsChunkRef> m_chunksQueued;
std::vector<DxvkCsChunkRef> m_chunksInjected;
dxvk::thread m_thread;
void threadFunc();