Files
LibretroAdmin 28b795b859 Core: nothing allocated on the heap for a frame that changes nothing
A retro_run that draws nothing new allocates nothing; before, it made
some thirty-six allocations:

- Option lookups by key (IsUpdated and GetCached, about thirty a run)
  made a std::string of the key for an unordered_map. The options are
  now an array in the order of their definitions with an index sorted
  by key, searched with strcmp.
- The JIT asks for its thread's stack bounds each time it starts
  running, every run with frame stepping, and glibc's
  pthread_getattr_np allocates. A thread's stack does not move: the
  bounds are kept per thread after the first time.
- Every event pushed to the video thread, two a field for the XFB
  swap, was built with new. Events are now built in a ring of fixed
  slots: at most the queue's 1024 wait and one runs, so a slot comes
  round again only once its event is done.
- A frame step, every run, posted a resume command to the real
  Wiimote manager, built with new. A momentary state change no longer
  resumes the remotes; a reported one still does.
2026-11-06 20:47:25 +01:00

68 lines
1.7 KiB
C++

// Copyright 2015 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoCommon/AsyncRequests.h"
#include "Core/System.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/VertexManagerBase.h"
AsyncRequests AsyncRequests::s_singleton;
AsyncRequests::AsyncRequests()
{
retro_waitable_spsc_init(&m_queue, QUEUE_REQUESTS * sizeof(Request*));
retro_eventcount_init(&m_completed);
}
AsyncRequests::~AsyncRequests()
{
retro_eventcount_free(&m_completed);
retro_waitable_spsc_free(&m_queue);
}
void AsyncRequests::PullEvents()
{
if (retro_spsc_read_avail(&m_queue.queue) < sizeof(Request*))
return;
// This is only called if the queue isn't empty.
// So just flush the pipeline to get accurate results.
g_vertex_manager->Flush();
Request* request;
while (retro_waitable_spsc_read(&m_queue, &request, sizeof(request)) == sizeof(request))
request->run(request);
}
void AsyncRequests::Submit(Request* request)
{
// Only waits when the video thread is QUEUE_REQUESTS requests behind.
while (!retro_waitable_spsc_wait_writable(&m_queue, sizeof(request), 1000000))
{
}
retro_waitable_spsc_write(&m_queue, &request, sizeof(request));
auto& system = Core::System::GetInstance();
system.GetFifo().RunGpu();
}
void AsyncRequests::WaitDone(retro_atomic_int_t* done)
{
while (!retro_atomic_load_acquire_int(done))
{
const int key = retro_eventcount_prepare_wait(&m_completed);
if (retro_atomic_load_acquire_int(done))
{
retro_eventcount_cancel_wait(&m_completed);
break;
}
retro_eventcount_commit_wait(&m_completed, key);
}
}
void AsyncRequests::SetPassthrough(bool enable)
{
m_passthrough = enable;
}