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:
parent
abd888a0bb
commit
438a08f87c
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user