DVD thread: results and their buffers used again

A result the DVD thread made goes back to it once the CPU thread has
finished with it, buffer and all, through a lock-free stack the DVD
thread drains when it runs out. Reads of compressed, encrypted and
assembled images allocate nothing once there are as many results as
reads in flight.
This commit is contained in:
LibretroAdmin authored and libretroadmin committed 2026-11-07 03:27:42 +01:00
1 parent 54b8264a05
commit ce91925b34
2 files changed
+38 -14

No files matched your search

+34 -14
View File
@@ -34,6 +34,7 @@ namespace DVD
DVDThread::DVDThread(Core::System& system) : m_system(system)
{
mpsc_stack_init(&m_result_queue);
mpsc_stack_init(&m_free_results);
retro_eventcount_init(&m_result_ready);
}
@@ -54,12 +55,17 @@ void DVDThread::FreeResults()
delete reinterpret_cast<ResultNode*>(node);
node = next;
}
mpsc_stack_node_t* queued = mpsc_stack_drain(&m_result_queue);
while (queued)
mpsc_stack_node_t* lists[3] = {mpsc_stack_drain(&m_result_queue),
mpsc_stack_drain(&m_free_results), m_worker_free};
m_worker_free = nullptr;
for (mpsc_stack_node_t* queued : lists)
{
mpsc_stack_node_t* const next = queued->next;
delete reinterpret_cast<ResultNode*>(queued);
queued = next;
while (queued)
{
mpsc_stack_node_t* const next = queued->next;
delete reinterpret_cast<ResultNode*>(queued);
queued = next;
}
}
}
@@ -332,6 +338,7 @@ void DVDThread::FinishRead(u64 id, s64 cycles_late)
// The DVD thread may finish reads in a different order than they are wanted, so results
// are looked up by id: in the map a savestate load filled, else among those that arrived.
ReadResult result;
ResultNode* node = nullptr;
auto it = m_result_map.find(id);
if (it != m_result_map.end())
{
@@ -340,7 +347,6 @@ void DVDThread::FinishRead(u64 id, s64 cycles_late)
}
else
{
ResultNode* node;
while (!(node = TakeResult(id)))
{
const int key = retro_eventcount_prepare_wait(&m_result_ready);
@@ -351,13 +357,11 @@ void DVDThread::FinishRead(u64 id, s64 cycles_late)
}
retro_eventcount_commit_wait(&m_result_ready, key);
}
result = std::move(node->result);
delete node;
}
// We have now obtained the right ReadResult.
const ReadRequest& request = result.first;
const std::vector<u8>& buffer = result.second;
const ReadRequest& request = node ? node->result.first : result.first;
const std::vector<u8>& buffer = node ? node->result.second : result.second;
DEBUG_LOG_FMT(DVDINTERFACE, "Disc has been read. Emulated time including delay: {} us.",
(m_system.GetCoreTiming().GetTicks() - request.time_started_ticks) /
@@ -386,19 +390,35 @@ void DVDThread::FinishRead(u64 id, s64 cycles_late)
// Notify the emulated software that the command has been executed
dvd_interface.FinishExecutingCommand(request.reply_type, interrupt, cycles_late, buffer);
if (node)
mpsc_stack_push(&m_free_results, &node->link);
}
// DVD thread. A result to fill: one handed back, or a new one while none has been.
DVDThread::ResultNode* DVDThread::TakeFreeResult()
{
mpsc_stack_node_t* node;
if (!m_worker_free)
m_worker_free = mpsc_stack_drain(&m_free_results);
node = m_worker_free;
if (!node)
return new ResultNode{{nullptr}, ReadResult()};
m_worker_free = node->next;
return reinterpret_cast<ResultNode*>(node);
}
void DVDThread::ProcessReadRequest(ReadRequest&& request)
{
m_file_logger.Log(*m_disc, request.partition, request.dvd_offset);
std::vector<u8> buffer(request.length);
ResultNode* const node = TakeFreeResult();
std::vector<u8>& buffer = node->result.second;
buffer.resize(request.length);
if (!m_disc->Read(request.dvd_offset, request.length, buffer.data(), request.partition))
buffer.resize(0);
node->result.first = std::move(request);
ResultNode* const node =
new ResultNode{{nullptr}, ReadResult(std::move(request), std::move(buffer))};
mpsc_stack_push(&m_result_queue, &node->link);
retro_eventcount_notify(&m_result_ready);
}
+4
View File
@@ -138,6 +138,10 @@ private:
ResultNode* TakeResult(u64 id);
void FreeResults();
// Results go back for the DVD thread to fill again, buffers and all.
ResultNode* TakeFreeResult();
mpsc_stack_t m_free_results;
mpsc_stack_node_t* m_worker_free = nullptr; // DVD thread only
mpsc_stack_t m_result_queue;
retro_eventcount_t m_result_ready;
mpsc_stack_node_t* m_result_chain = nullptr; // CPU thread only