Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test Compile #4

Merged
merged 192 commits into from
Feb 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
192 commits
Select commit Hold shift + click to select a range
42e62fa
[Kernel] Implement ObCreateObject
disjtqz Oct 15, 2023
6ea5957
[Kernel] Stub out xeObSplitName until cleaner version can be written
disjtqz Oct 15, 2023
ef5cb60
[Kernel] shrink ObCreateObject
disjtqz Oct 15, 2023
fd3b832
managed to get xexs loaded under nukernel
disjtqz Oct 18, 2023
19232d3
add ipi code for cp interrupt, cp thread and graphics system thread a…
disjtqz Oct 18, 2023
3c562d0
xma decoder no longer on xthread
disjtqz Oct 18, 2023
e3de2fc
actually run scheduled fibers!
disjtqz Oct 18, 2023
425f3cc
audiosystem uses helper thread to call guest code, majority of execut…
disjtqz Oct 18, 2023
eaf103f
IPIs work now! But we deadlock waiting on CP, CP deadlocks waiting on…
disjtqz Oct 18, 2023
3881c15
attempted a less racy way of IPI'ing, with no success
disjtqz Oct 18, 2023
2921a28
share kpcr on thread
disjtqz Oct 18, 2023
30c42ca
Add deferred ipi workers
disjtqz Oct 19, 2023
5f29cf8
add hwclock
disjtqz Oct 19, 2023
b04d5d1
terrible hacks to get interrupts working again
disjtqz Oct 19, 2023
76a66e5
Move guest kernel structures to dedicated kernel_guest_structures header
disjtqz Oct 19, 2023
f4948f9
add KWAIT_BLOCK structure from old lle
disjtqz Oct 19, 2023
0a7569d
further flesh out kthread, add stub timer structures
disjtqz Oct 19, 2023
57cfe02
flesh out kpcr/idle thread bootup more
disjtqz Oct 19, 2023
87c0bda
begin implementing dispatch header objects
disjtqz Oct 19, 2023
24936c6
flesh out timer further, started work on timer table
disjtqz Oct 20, 2023
45f5be8
partial scheduler implementation
disjtqz Oct 20, 2023
12de4dd
Fixed crash from uninitialized timer list
disjtqz Oct 20, 2023
811e3a5
idle loop looks complete now
disjtqz Oct 20, 2023
47224ed
hwclock paused until after threads start
disjtqz Oct 21, 2023
0ded3d7
add EZPointer structure, because I'm tired of writing out TranslateVi…
disjtqz Oct 21, 2023
9273e5e
implement xeHandleReadyThreadOnDifferentProcessor
disjtqz Oct 21, 2023
3a6a54f
Add hacky, slow fallback for cpu interrupts that does everything in s…
disjtqz Oct 21, 2023
d3cddbe
Execute initialization on a kthread (incorrectly)
disjtqz Oct 21, 2023
debaec1
rework kernel boot to match real kernel.
disjtqz Oct 21, 2023
1a3df45
implement decrementer + decrementer interrupt (for timeslice expiration)
disjtqz Oct 21, 2023
ec3963b
initial implementation of xenon external interrupt controller
disjtqz Oct 22, 2023
17c250e
set the interrupt priority in lower/raise irql
disjtqz Oct 22, 2023
2b6cf5f
implemented xeSelectThreadDueToTimesliceExpiration
disjtqz Oct 22, 2023
1560189
Actually have things drawing onscreen now!
disjtqz Oct 22, 2023
9ef394f
Disable interrupts in interrupt handler, handlers that allow other in…
disjtqz Oct 22, 2023
252fe69
fix slowness in IPI code by adding some maybeyields to spins
disjtqz Oct 23, 2023
62562fe
reimplement NtYieldExecution
disjtqz Oct 23, 2023
bfc748e
made dispatch thread nonblocking w/ atomic list, yield to scheduler
disjtqz Oct 23, 2023
bbe6239
working on implementing dispatcher objects/waiting
disjtqz Oct 23, 2023
b915735
More frequent interrupt checks
disjtqz Oct 24, 2023
45cbe5d
add Ke timer implementations
disjtqz Oct 24, 2023
c2b2919
fully-ish implement timers
disjtqz Oct 24, 2023
45a6442
made some xthread changes, now nothing works!
disjtqz Oct 24, 2023
326f43b
woops! was mixing up unk_mask_64 with the has_ready mask. now things …
disjtqz Oct 24, 2023
fb9b87a
set process pointer in idle threads on boot
disjtqz Oct 24, 2023
be86345
deliver kernel apcs on thread startup too
disjtqz Oct 24, 2023
9b18b73
"implement" xeKeWaitForSingleObject
disjtqz Oct 25, 2023
7f36e5a
Add correct timebase frequency, add mismatched KeQueryPerformanceFreq…
disjtqz Oct 26, 2023
3864936
in hindsight, not a good idea to bind the idle process threadstate in…
disjtqz Oct 26, 2023
416f886
add SCHEDLOG
disjtqz Oct 26, 2023
5570cb3
fix semaphore
disjtqz Oct 26, 2023
170d671
Quake2 makes it to the menu!!!
disjtqz Oct 26, 2023
1168284
stub out waitformultiple
disjtqz Oct 26, 2023
ebb2c5b
minor cleanup
disjtqz Oct 26, 2023
c053c77
add code for saving/restoring gprs from host code
disjtqz Oct 27, 2023
663e2d9
remove ThreadState memory_ field
disjtqz Oct 27, 2023
5259432
Eliminate ThreadState processor pointer, threadstate now only contain…
disjtqz Oct 27, 2023
64e30cc
Replace calls to new ThreadState with calls to ThreadState::Create
disjtqz Oct 27, 2023
55a8e2d
ThreadState now is just a PPCContext that has been reinterpret_cast
disjtqz Oct 27, 2023
8efc8ff
remove thread_state pointer from PPCContext now that they are the sam…
disjtqz Oct 27, 2023
2741f13
convert nullptr in ppc context TranslateVirtual/HostToGuestVirtual
disjtqz Oct 27, 2023
70661d4
dont call xeProcessKernelApcs/DeliverApcs after KfLowerIrql in XThrea…
disjtqz Oct 27, 2023
23fd44a
Discovered that apc_software_interrupt_state needs to be set by defer…
disjtqz Oct 27, 2023
6a6959c
implement signalandwaitforsingleobject + fix its prototype, its been …
disjtqz Oct 28, 2023
d84a2b2
create non-idle thread objects through xeObCreateObject
disjtqz Oct 28, 2023
d0f937b
implement KePulseEvent, NtPulseEvent, NtQueryEvent,KeSetAffinityThrea…
disjtqz Oct 28, 2023
aa8cda1
Directly pass semaphore pointer in xeKeReleaseSemaphore
disjtqz Oct 28, 2023
0ec8b0a
Change AcquireSpinlock/ReleaseSpinlock to no longer call raise/lower …
disjtqz Oct 28, 2023
79f32cb
implement xeKeWaitForMultipleObjects, implement KeWaitForMultipleObje…
disjtqz Oct 29, 2023
0c2a682
Add OPCODE_CHECK_INTERRUPT, implement r13 only context barriers for i…
disjtqz Oct 29, 2023
b9641cf
kernel dispatch thread runs now
disjtqz Oct 29, 2023
2103a35
initialize lsit head in critical section
disjtqz Oct 29, 2023
77ed9f0
implement xeKeSetDisableBoostThread
disjtqz Oct 30, 2023
60c5ff5
Fix timers and post-wait thread enqueues, but now everything crashes
disjtqz Oct 30, 2023
24c46cc
bean now boots!
disjtqz Oct 30, 2023
d4cacc6
lock dispatcher in clock interrupt when checking timers (possible dea…
disjtqz Oct 31, 2023
ae9ae22
zero out apc requests when honoring them
disjtqz Oct 31, 2023
4849a27
Add extra logging for suspend/entercriticalsection
disjtqz Nov 2, 2023
84e61cf
fix TrapDebugPrint to use length in r4
disjtqz Nov 2, 2023
c0883fd
remove critical section logging, return status in xeKeReleaeMutant.
disjtqz Nov 2, 2023
7280299
Add simple RtlRaiseStatus helper, fix status return values for NtRele…
disjtqz Nov 2, 2023
2252085
introduce a delay to the audio thread, and now sound works!
disjtqz Nov 2, 2023
0ecb40e
A good many games now boot. some are even playable
disjtqz Nov 3, 2023
34e5bed
expose KeSetTimer, KeSetTimerEx, KeCancelTimer and KeReleaseMutant to…
disjtqz Nov 3, 2023
751cb0b
hack to get games that do XamTaskSchedule working
disjtqz Nov 3, 2023
431352c
Initial XNotifyListener work
disjtqz Nov 3, 2023
eba9c72
implement native XNotifyListener
disjtqz Nov 3, 2023
c2d2b1e
Do delete_proc stuff in XMutant/XTimer dctor
disjtqz Nov 3, 2023
c6d14db
removed global KernelState tls_bitmap, use per-X_KPROCESS tls bitmap now
disjtqz Nov 3, 2023
7b80a6b
initialize ts bundle on boot, fixed several games
disjtqz Nov 3, 2023
1d231d2
initialize timestamp bundle with guest tick count, not host
disjtqz Nov 4, 2023
47e87cd
Exposing reservation emulation to kernel/host code
disjtqz Nov 4, 2023
c223bc5
much crashier now :(
disjtqz Nov 4, 2023
2ee54fe
Correct endian for critical section lock count
disjtqz Nov 4, 2023
3713f94
nasty reserve hacks; re-enable guest_ipi_dispatch_event
disjtqz Nov 5, 2023
d337df3
Add wrappers around NtWaitForAlertByThreadId/NtAlertThreadById
disjtqz Nov 5, 2023
bbe7b39
Expose critical section methods outside of xboxkrnl_rtl
disjtqz Nov 5, 2023
c017a13
add X_KQUEUE structure from nt sdk
disjtqz Nov 5, 2023
c4e60df
implement KeInitializeQueue, KeInsertQueue, KeInsertHeadQueue
disjtqz Nov 5, 2023
d04a5f4
Changes to prevent timer drift, but now quantum decrementing might po…
disjtqz Nov 5, 2023
b2ededb
Changes to a few IPIs, different behavior if running from idle thread
disjtqz Nov 5, 2023
7b23e0b
Implement background scheduling
disjtqz Nov 6, 2023
3ded70b
Add code for calculating an rdtsc timestamp that can be compared with…
disjtqz Nov 8, 2023
543455b
Allow queueing up multiple interrupt requests
disjtqz Nov 9, 2023
e197600
pass context, interrupt request to ipi wrapper
disjtqz Nov 9, 2023
9ac6710
initial implementation of "timed interrupts", for which the timing is…
disjtqz Nov 9, 2023
d2a6a2f
use microseconds instead of nanoseconds for timed interrupts
disjtqz Nov 9, 2023
20e0b06
Use timed interrupt instead of HWClock for clock interrupt
disjtqz Nov 10, 2023
46f8299
reduce cpu usage by introducing 100microsecond wait in idle process loop
disjtqz Nov 10, 2023
a196595
semi-implement EOI signal, fixing many freezes.
disjtqz Nov 11, 2023
d741694
implement xeKeSignalQueue, call it in necessary places
disjtqz Nov 11, 2023
8736c06
create initialization systemthread
disjtqz Nov 11, 2023
ffd6e6e
start audiosystem worker thread from kernel boot. remove jenky interr…
disjtqz Nov 11, 2023
e7b52a6
flesh out xamscheduletask further
disjtqz Nov 11, 2023
6ca118e
fix cp interrupt, was always being treated as vblank interrupt!
disjtqz Nov 11, 2023
8d8f83b
implement KeRundownQueue
disjtqz Nov 12, 2023
33f203b
implement KeRemoveQueue, which wraps up Queue object implementation
disjtqz Nov 12, 2023
82256a4
XThread destructor now gets executed
disjtqz Nov 12, 2023
575f70c
re-split threadid and handle
disjtqz Nov 12, 2023
fb95f03
switched ExThreadObjectType's alloc/free procs to just allocatepool/f…
disjtqz Nov 13, 2023
418611d
semi-implement KeSaveFloatingPointState/KeRestoreFloatingPointState
disjtqz Nov 14, 2023
ce9078d
save/restore crs + xer, fixing many crashes
disjtqz Nov 14, 2023
df5f3fb
no longer use nasty hack interrupt to launch module
disjtqz Nov 16, 2023
6dd0fcc
only check interrupts every 256 basic blocks
disjtqz Nov 16, 2023
525d63d
Use timed interrupts for vsync interrupt
disjtqz Nov 16, 2023
467da21
hoist generic external interrupt epilog to topmost interrupt handler …
disjtqz Nov 19, 2023
0e1dbdf
set affinities of threads that emulate non-cpu hardware to hw threads…
disjtqz Nov 19, 2023
93d0a7b
implemented on_interrupt_stack properly
disjtqz Nov 19, 2023
fd309ac
assert if timers are owned by thread on termination
disjtqz Nov 19, 2023
9630860
add optimized uint32/uint64 appending methods to stringbuffer.
disjtqz Nov 20, 2023
f698652
disable waiting for audiosystem callbacks, was causing audio issues
disjtqz Nov 21, 2023
43a8a5a
create xamtaskschedule thread as a system thread. the system priority…
disjtqz Nov 21, 2023
973e293
rename some X_KTHREAD/X_KPROCESS fields based on info from cxbx-r
disjtqz Nov 22, 2023
c69cbff
Add StringBuffer::Reserve
disjtqz Nov 22, 2023
9160da9
add Emulator::Get
disjtqz Nov 22, 2023
5347208
default hid to xinput for now
disjtqz Nov 22, 2023
9aaa1e7
fix race condition in startup; Emulator::WaitUntilExit could try to w…
disjtqz Nov 24, 2023
bec76c0
for guest threads, use cpu number instead of thread id in logging
disjtqz Nov 24, 2023
2b93ad0
Set main thread priority to 0xE, currently unsure why we have a mismatch
disjtqz Nov 24, 2023
c52f225
Add checks that guest critical section is okay
disjtqz Nov 24, 2023
e07a6b0
assert if doing get waitableobject on file or iocompletion, as theyre…
disjtqz Nov 24, 2023
676e720
dont assert, just log if XFileBasicInformation is passed to NtSetInfo…
disjtqz Nov 24, 2023
1471b5e
assert !wait in XEvent->Set
disjtqz Nov 24, 2023
adf270b
move xboxkrnl video exports to KernelGuestGlobals, theyre also no lon…
disjtqz Nov 24, 2023
31ba380
add DISPATCHER_ enum, use in a few places
disjtqz Nov 24, 2023
0cdc8a3
guesstimated implementation of audio interrupt; all NtYieldExecutions…
disjtqz Nov 24, 2023
a2a9a0a
process audio callbacks one at a time, no flushing
disjtqz Nov 24, 2023
904cd73
Revert "process audio callbacks one at a time, no flushing"
disjtqz Nov 24, 2023
8b530eb
implement "fake fibers" via threads, allows for easier debugging of f…
disjtqz Nov 25, 2023
5338520
corrected the ordering of AppendHex functions for logging
disjtqz Nov 25, 2023
43f4767
proper termination for fake fibers
disjtqz Nov 26, 2023
051b3aa
implement constant mmio address inlining so that guest to host thunk …
disjtqz Nov 26, 2023
991db98
fix bug in kernel apcs, was overwriting arg 2
disjtqz Nov 26, 2023
a930fe3
implement own critical section impl for global critical region to giv…
disjtqz Nov 27, 2023
1fb24a9
add preprocessor macro that enables/disables saving fpu+vpu as part o…
disjtqz Nov 27, 2023
c1c1cc3
add initial implementation of timebase timing fences
disjtqz Nov 27, 2023
8ff6c04
disable very long sleep in "XMPGetPlaybackController"
disjtqz Nov 27, 2023
aa2a564
add timing fences in video init functions
disjtqz Nov 27, 2023
beae58a
timing fence for mmgetphysicaladdress
disjtqz Nov 27, 2023
1096fb5
recursion count must be > 0 in RtlLeaveCriticalSection if case, chang…
disjtqz Nov 27, 2023
b1c6a26
timing fence for XamInputGetState
disjtqz Nov 27, 2023
c847166
setup r[2] constant value, only used by HV afaik
disjtqz Jan 8, 2024
d544fa9
synchronize core timebases
disjtqz Jan 8, 2024
ca53b4e
approx timing fences for video functions
disjtqz Jan 8, 2024
a52afeb
clean up xeKeEnterBackgroundMode
disjtqz Jan 8, 2024
8b8ff44
assign names to some background scheduling related variables
disjtqz Jan 8, 2024
f9c85b8
Re-enable xmp_app long sleep
disjtqz Jan 8, 2024
950f32e
turned unk_154/unk_158 into an X_LIST_ENTRY
disjtqz Jan 8, 2024
4577b09
Removed old useless cvar that toggles off software interrupt handling.
disjtqz Jan 8, 2024
a2841b0
Added a GetKThread variant that uses an existing pcr pointer
disjtqz Jan 18, 2024
26e882d
Changed some unnamed constants to their IRQL_ enum values; changed se…
disjtqz Jan 18, 2024
1c8cf6d
unk_0A is a short
disjtqz Jan 22, 2024
879566f
implement KeRetireDpcList
disjtqz Jan 22, 2024
5767b07
restore IdleSleep in idle process loop now that the recursive interru…
disjtqz Jan 24, 2024
8cf64c2
added named constants for X_KTHREAD's thread_state field
disjtqz Jan 24, 2024
5bf3655
Interrupt checks were not properly being emitted at the start of ever…
disjtqz Jan 24, 2024
e18d115
only check running timers if a timer is not pending; use addressof X_…
disjtqz Jan 25, 2024
2c08f6a
Add additional critical section checks
disjtqz Jan 25, 2024
ddc250f
add a special assert for XamTaskSchedule type 4 task (h4 seems to use…
disjtqz Jan 25, 2024
607c9ba
clean up SystemClockInterrupt, add IRQL_CLOCK
disjtqz Jan 25, 2024
d3b0f89
change incorrect comment about timed interrupt length for clock, its …
disjtqz Jan 25, 2024
92dd50e
Refactor XamTaskSchedule, splitting off "XamThreadCreate" from it for…
disjtqz Jan 25, 2024
5a4df1c
add missing return in XamTaskSchedule
disjtqz Jan 25, 2024
9d07f9d
Clean up kernel_state_boot, found a potentially bad bug where cpu 0's…
disjtqz Jan 26, 2024
0ea2678
assert timer reinsert succeeded
disjtqz Jan 26, 2024
6664fe1
gave a name to the last param of xeAllocatePoolTypeWithTag, appears t…
disjtqz Jan 26, 2024
fa09f57
Select interrupts based on their priorities and the order in which th…
disjtqz Jan 27, 2024
675294f
return true if CheckInterrupt executed an interrupt
disjtqz Jan 27, 2024
5383707
Delay adding interrupt checks to the starts of blocks until after con…
disjtqz Jan 28, 2024
dcc7176
Merge pull request #1 from disjtqz/interrupt_prioritization
disjtqz Jan 28, 2024
8eb64ce
Seems to fix the crashes introduced by 5bf3655
disjtqz Jan 28, 2024
9016938
add cvar no_idle_sleeping_for_hw_threads to make testing idlesleep vs…
disjtqz Feb 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/xenia/app/xenia_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
DEFINE_string(apu, "any", "Audio system. Use: [any, nop, sdl, xaudio2]", "APU");
DEFINE_string(gpu, "any", "Graphics system. Use: [any, d3d12, vulkan, null]",
"GPU");
DEFINE_string(hid, "any", "Input system. Use: [any, nop, sdl, winkey, xinput]",
DEFINE_string(hid, "xinput", "Input system. Use: [any, nop, sdl, winkey, xinput]",
"HID");

DEFINE_path(
Expand Down
125 changes: 101 additions & 24 deletions src/xenia/apu/audio_system.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
#include "xenia/base/string_buffer.h"
#include "xenia/base/threading.h"
#include "xenia/cpu/thread_state.h"
#include "xenia/emulator.h"
#include "xenia/kernel/kernel_state.h"

#include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h"
// As with normal Microsoft, there are like twelve different ways to access
// the audio APIs. Early games use XMA*() methods almost exclusively to touch
// decoders. Later games use XAudio*() and direct memory writes to the XMA
Expand All @@ -35,13 +36,19 @@
// and let the normal AudioSystem handling take it, to prevent duplicate
// implementations. They can be found in xboxkrnl_audio_xma.cc

DEFINE_uint32(
apu_max_queued_frames, 64,
"Allows changing max buffered audio frames to reduce audio delay. Minimum is 16.", "APU");
DEFINE_uint32(apu_max_queued_frames, 64,
"Allows changing max buffered audio frames to reduce audio "
"delay. Minimum is 16.",
"APU");

#define AUDIOSYSTEM_NOWAIT_FOR_CALLBACK 1
namespace xe {
namespace apu {

struct GuestMessage {
threading::AtomicListEntry list_entry;
uint32_t client_callback_;
uint32_t client_callback_arg_;
};
AudioSystem::AudioSystem(cpu::Processor* processor)
: memory_(processor->memory()),
processor_(processor),
Expand All @@ -60,6 +67,7 @@ AudioSystem::AudioSystem(cpu::Processor* processor)
xma_decoder_ = std::make_unique<xe::apu::XmaDecoder>(processor_);

resume_event_ = xe::threading::Event::CreateAutoResetEvent(false);
signal_event_ = xe::threading::Event::CreateAutoResetEvent(false);
assert_not_null(resume_event_);
}

Expand All @@ -74,21 +82,78 @@ X_STATUS AudioSystem::Setup(kernel::KernelState* kernel_state) {
if (result) {
return result;
}

kernel_state_ = kernel_state;
worker_running_ = true;
worker_thread_ = kernel::object_ref<kernel::XHostThread>(
new kernel::XHostThread(kernel_state, 128 * 1024, 0, [this]() {
WorkerThreadMain();
return 0;
}, kernel_state->GetSystemProcess()));

threading::Thread::CreationParameters crparams{};
worker_thread_ = threading::Thread::Create(
crparams, std::bind(&AudioSystem::WorkerThreadMain, this));
Emulator::Get()->RegisterGuestHardwareBlockThread(worker_thread_.get());
// As we run audio callbacks the debugger must be able to suspend us.
worker_thread_->set_can_debugger_suspend(true);
worker_thread_->set_name("Audio Worker");
worker_thread_->Create();
worker_thread_->set_affinity_mask(0b11000000);

return X_STATUS_SUCCESS;
}

void AudioSystem::StartGuestWorkerThread(kernel::KernelState* kernel) {
xenia_assert(!guest_thread_);
auto context = cpu::ThreadState::GetContext();
guest_thread_ =
kernel::object_ref<kernel::XHostThread>(new kernel::XHostThread(
kernel, 65536U, 0x10000083u,
[this]() {
std::vector<GuestMessage*> messages_rev{};
messages_rev.reserve(128);
auto context = cpu::ThreadState::GetContext();
while (true) {
kernel::xboxkrnl::xeKeWaitForSingleObject(
context,
&context->kernel_state->GetKernelGuestGlobals(context)
->audio_interrupt_dpc_event_.header,
0, 0, 0, nullptr);

auto callbacks = guest_worker_messages_.Flush();

if (!callbacks) {
//xenia_assert(false);
continue;
}
kernel::xboxkrnl::xeKeEnterCriticalRegion(context);
while (callbacks) {
messages_rev.push_back((GuestMessage*)callbacks);
callbacks = callbacks->next_;
context->CheckInterrupt();
}
std::reverse(messages_rev.begin(), messages_rev.end());

for (auto&& order : messages_rev) {
uint64_t args[] = {order->client_callback_arg_};
auto kpcr = kernel::GetKPCR(context);

auto current_irql = kpcr->current_irql;

xenia_assert(current_irql == kernel::IRQL_PASSIVE);
this->processor()->Execute(context->thread_state(),
order->client_callback_, args,
countof(args));
delete order;
context->CheckInterrupt();
#if AUDIOSYSTEM_NOWAIT_FOR_CALLBACK == 0
signal_event_->Set();
#endif
}
messages_rev.clear();
kernel::xboxkrnl::xeKeLeaveCriticalRegion(context);
}
return true;
},
kernel->GetSystemProcess()));
guest_thread_->Create();
kernel::xboxkrnl::xeKeSetPriorityThread(
context, guest_thread_->guest_object<kernel::X_KTHREAD>(), 25);
kernel::xboxkrnl::xeKeResumeThread(
context, guest_thread_->guest_object<kernel::X_KTHREAD>());
}
void AudioSystem::WorkerThreadMain() {
// Initialize driver and ringbuffer.
Initialize();
Expand Down Expand Up @@ -120,19 +185,28 @@ void AudioSystem::WorkerThreadMain() {
bool pumped = false;
if (result.first == xe::threading::WaitResult::kSuccess) {
auto index = result.second;

auto global_lock = global_critical_region_.Acquire();
uint32_t client_callback = clients_[index].callback;
uint32_t client_callback_arg = clients_[index].wrapped_callback_arg;
global_lock.unlock();

if (client_callback) {
SCOPE_profile_cpu_i("apu", "xe::apu::AudioSystem->client_callback");
uint64_t args[] = {client_callback_arg};
processor_->Execute(worker_thread_->thread_state(), client_callback,
args, xe::countof(args));
client_callback_arg_in_ = client_callback_arg;
client_callback_in_ = client_callback;

auto msg = new GuestMessage();
msg->client_callback_ = client_callback_in_;
msg->client_callback_arg_ = client_callback_arg_in_;
guest_worker_messages_.Push(&msg->list_entry);
{
cpu::SendInterruptArguments interrupt_arguments{};
interrupt_arguments.ipi_func = &kernel::KernelState::AudioInterrupt;
interrupt_arguments.ud = nullptr;
interrupt_arguments.wait_done = false;
interrupt_arguments.irql_ = kernel::IRQL_AUDIO;
processor()->GetCPUThread(4)->SendGuestIPI(interrupt_arguments);
}

#if AUDIOSYSTEM_NOWAIT_FOR_CALLBACK == 0
threading::Wait(signal_event_.get(), false);
#endif
pumped = true;
}

Expand Down Expand Up @@ -167,7 +241,8 @@ void AudioSystem::Shutdown() {
worker_running_ = false;
shutdown_event_->Set();
if (worker_thread_) {
worker_thread_->Wait(0, 0, 0, nullptr);
threading::Wait(worker_thread_.get(), false);
Emulator::Get()->UnregisterGuestHardwareBlockThread(worker_thread_.get());
worker_thread_.reset();
}
}
Expand Down Expand Up @@ -290,7 +365,9 @@ bool AudioSystem::Restore(ByteStream* stream) {
auto status = CreateDriver(id, client_semaphore, &driver);
if (XFAILED(status)) {
XELOGE(
"AudioSystem::Restore - Call to CreateDriver failed with status "
"AudioSystem::Restore - "
"Call to CreateDriver "
"failed with status "
"{:08X}",
status);
return false;
Expand Down
14 changes: 12 additions & 2 deletions src/xenia/apu/audio_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,17 @@ class AudioSystem {
void Pause();
void Resume();

//called by kernelstate in boot. actually called prior to Setup
void StartGuestWorkerThread(kernel::KernelState* kernel);
protected:
explicit AudioSystem(cpu::Processor* processor);

virtual void Initialize();

void WorkerThreadMain();



virtual X_STATUS CreateDriver(size_t index,
xe::threading::Semaphore* semaphore,
AudioDriver** out_driver) = 0;
Expand All @@ -69,12 +73,13 @@ class AudioSystem {

Memory* memory_ = nullptr;
cpu::Processor* processor_ = nullptr;
kernel::KernelState* kernel_state_ = nullptr;
std::unique_ptr<XmaDecoder> xma_decoder_;
uint32_t queued_frames_;

std::atomic<bool> worker_running_ = {false};
kernel::object_ref<kernel::XHostThread> worker_thread_;

std::unique_ptr<threading::Thread> worker_thread_;
kernel::object_ref<kernel::XHostThread> guest_thread_;
xe::global_critical_region global_critical_region_;
static const size_t kMaximumClientCount = 8;
struct {
Expand All @@ -96,6 +101,11 @@ class AudioSystem {
bool paused_ = false;
threading::Fence pause_fence_;
std::unique_ptr<threading::Event> resume_event_;
std::unique_ptr<threading::Event> signal_event_;
uint32_t client_callback_in_;
uint32_t client_callback_arg_in_;

threading::AtomicListHeader guest_worker_messages_;
};

} // namespace apu
Expand Down
16 changes: 15 additions & 1 deletion src/xenia/apu/xma_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,20 @@ int XmaContext::Setup(uint32_t id, Memory* memory, uint32_t guest_ptr) {
return 0;
}

bool XmaContext::is_allocated() {
return XmaDecoder::BoolsForContext(this)->is_allocated_;
}
bool XmaContext::is_enabled() {
return XmaDecoder::BoolsForContext(this)->is_enabled_;
}

void XmaContext::set_is_allocated(bool is_allocated) {
XmaDecoder::BoolsForContext(this)->is_allocated_ = is_allocated;
}
void XmaContext::set_is_enabled(bool is_enabled) {
XmaDecoder::BoolsForContext(this)->is_enabled_ = is_enabled;
}

bool XmaContext::Work() {
if (!is_enabled() || !is_allocated()) {
return false;
Expand Down Expand Up @@ -168,7 +182,7 @@ void XmaContext::Disable() {
void XmaContext::Release() {
// Lock it in case the decoder thread is working on it now.
std::lock_guard<xe_mutex> lock(lock_);
assert_true(is_allocated_ == true);
assert_true(is_allocated() == true);

set_is_allocated(false);
auto context_ptr = memory()->TranslateVirtual(guest_ptr());
Expand Down
15 changes: 9 additions & 6 deletions src/xenia/apu/xma_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ struct Xma2ExtraData {
static_assert_size(Xma2ExtraData, 34);
#pragma pack(pop)

struct XmaContextBools {
volatile bool is_allocated_ = false;
volatile bool is_enabled_ = false;
};

class XmaContext {
public:
static const uint32_t kBytesPerPacket = 2048;
Expand Down Expand Up @@ -163,11 +168,11 @@ class XmaContext {

uint32_t id() { return id_; }
uint32_t guest_ptr() { return guest_ptr_; }
bool is_allocated() { return is_allocated_; }
bool is_enabled() { return is_enabled_; }
bool is_allocated();
bool is_enabled();

void set_is_allocated(bool is_allocated) { is_allocated_ = is_allocated; }
void set_is_enabled(bool is_enabled) { is_enabled_ = is_enabled; }
void set_is_allocated(bool is_allocated);
void set_is_enabled(bool is_enabled);

private:
static void SwapInputBuffer(XMA_CONTEXT_DATA* data);
Expand Down Expand Up @@ -205,8 +210,6 @@ class XmaContext {
uint32_t id_ = 0;
uint32_t guest_ptr_ = 0;
xe_mutex lock_;
volatile bool is_allocated_ = false;
volatile bool is_enabled_ = false;
// bool is_dirty_ = true;

// ffmpeg structures
Expand Down
37 changes: 26 additions & 11 deletions src/xenia/apu/xma_decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
#include "xenia/base/string_buffer.h"
#include "xenia/cpu/processor.h"
#include "xenia/cpu/thread_state.h"
#include "xenia/kernel/xthread.h"
#include "xenia/emulator.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/xthread.h"
extern "C" {
#include "third_party/FFmpeg/libavutil/log.h"
} // extern "C"
Expand Down Expand Up @@ -102,8 +103,7 @@ void av_log_callback(void* avcl, int level, const char* fmt, va_list va) {
StringBuffer buff;
buff.AppendVarargs(fmt, va);
xe::logging::AppendLogLineFormat(LogSrc::Apu, log_level, level_char,
"ffmpeg: {}",
buff.to_string_view());
"ffmpeg: {}", buff.to_string_view());
}

X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
Expand Down Expand Up @@ -141,24 +141,38 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
worker_running_ = true;
work_event_ = xe::threading::Event::CreateAutoResetEvent(false);
assert_not_null(work_event_);
worker_thread_ = kernel::object_ref<kernel::XHostThread>(
new kernel::XHostThread(kernel_state, 128 * 1024, 0, [this]() {
WorkerThreadMain();
return 0;
}, kernel_state->GetIdleProcess()));//this one doesnt need any process actually. never calls any guest code
threading::Thread::CreationParameters crparams{};
crparams.stack_size = 16 * 1024 * 1024;
worker_thread_ = threading::Thread::Create(
crparams, std::bind(&XmaDecoder::WorkerThreadMain, this));
Emulator::Get()->RegisterGuestHardwareBlockThread(worker_thread_.get());
worker_thread_->set_name("XMA Decoder");
worker_thread_->set_can_debugger_suspend(true);
worker_thread_->Create();
worker_thread_->set_affinity_mask(0b11000000);

return X_STATUS_SUCCESS;
}
XmaContextBools* XmaDecoder::BoolsForContext(XmaContext* context) {
size_t delta_to_context_bools =
offsetof(XmaDecoder, contexts_) - offsetof(XmaDecoder, context_bools_);

size_t delta_to_context_base = context->id() * sizeof(XmaContext);

return reinterpret_cast<XmaContextBools*>(
((reinterpret_cast<uintptr_t>(context) - delta_to_context_base) -
delta_to_context_bools) +
context->id() * sizeof(XmaContextBools));
}

void XmaDecoder::WorkerThreadMain() {
uint32_t idle_loop_count = 0;
while (worker_running_) {
// Okay, let's loop through XMA contexts to find ones we need to decode!
bool did_work = false;
for (uint32_t n = 0; n < kContextCount; n++) {
if (!this->context_bools_[n].is_enabled_ ||
!this->context_bools_[n].is_allocated_) {
continue;
}
XmaContext& context = contexts_[n];
did_work = context.Work() || did_work;

Expand Down Expand Up @@ -195,7 +209,8 @@ void XmaDecoder::Shutdown() {

if (worker_thread_) {
// Wait for work thread.
xe::threading::Wait(worker_thread_->thread(), false);
xe::threading::Wait(worker_thread_.get(), false);
Emulator::Get()->UnregisterGuestHardwareBlockThread(worker_thread_.get());
worker_thread_.reset();
}

Expand Down
Loading
Loading