XMA: Use a threadsafe bitmap to acquire/release contexts

Support Pausing/Resuming
This commit is contained in:
Dr. Chat 2016-07-28 21:11:12 -05:00
parent 69bb6aacef
commit f81a99e83a
3 changed files with 52 additions and 14 deletions

View File

@ -301,6 +301,8 @@ void AudioSystem::Pause() {
// Kind of a hack, but it works. // Kind of a hack, but it works.
shutdown_event_->Set(); shutdown_event_->Set();
pause_fence_.Wait(); pause_fence_.Wait();
xma_decoder_->Pause();
} }
void AudioSystem::Resume() { void AudioSystem::Resume() {
@ -310,6 +312,8 @@ void AudioSystem::Resume() {
paused_ = false; paused_ = false;
resume_event_->Set(); resume_event_->Set();
xma_decoder_->Resume();
} }
} // namespace apu } // namespace apu

View File

@ -115,6 +115,7 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
} }
} }
registers_.next_context = 1; registers_.next_context = 1;
context_bitmap_.Resize(kContextCount);
worker_running_ = true; worker_running_ = true;
worker_thread_ = kernel::object_ref<kernel::XHostThread>( worker_thread_ = kernel::object_ref<kernel::XHostThread>(
@ -141,6 +142,12 @@ void XmaDecoder::WorkerThreadMain() {
// registers_.current_context = n; // registers_.current_context = n;
// registers_.next_context = (n + 1) % kContextCount; // registers_.next_context = (n + 1) % kContextCount;
} }
if (paused_) {
pause_fence_.Signal();
resume_fence_.Wait();
}
xe::threading::MaybeYield(); xe::threading::MaybeYield();
} }
} }
@ -150,6 +157,10 @@ void XmaDecoder::Shutdown() {
worker_fence_.Signal(); worker_fence_.Signal();
worker_thread_.reset(); worker_thread_.reset();
if (paused_) {
Resume();
}
memory()->SystemHeapFree(registers_.context_array_ptr); memory()->SystemHeapFree(registers_.context_array_ptr);
} }
@ -164,32 +175,29 @@ int XmaDecoder::GetContextId(uint32_t guest_ptr) {
} }
uint32_t XmaDecoder::AllocateContext() { uint32_t XmaDecoder::AllocateContext() {
std::lock_guard<std::mutex> lock(lock_); size_t index = context_bitmap_.Acquire();
if (index == -1) {
for (uint32_t n = 0; n < kContextCount; n++) { // Out of contexts.
XmaContext& context = contexts_[n]; return 0;
if (!context.is_allocated()) {
context.set_is_allocated(true);
return context.guest_ptr();
}
} }
return 0; XmaContext& context = contexts_[index];
assert_false(context.is_allocated());
context.set_is_allocated(true);
return context.guest_ptr();
} }
void XmaDecoder::ReleaseContext(uint32_t guest_ptr) { void XmaDecoder::ReleaseContext(uint32_t guest_ptr) {
std::lock_guard<std::mutex> lock(lock_);
auto context_id = GetContextId(guest_ptr); auto context_id = GetContextId(guest_ptr);
assert_true(context_id >= 0); assert_true(context_id >= 0);
XmaContext& context = contexts_[context_id]; XmaContext& context = contexts_[context_id];
assert_true(context.is_allocated());
context.Release(); context.Release();
context_bitmap_.Release(context_id);
} }
bool XmaDecoder::BlockOnContext(uint32_t guest_ptr, bool poll) { bool XmaDecoder::BlockOnContext(uint32_t guest_ptr, bool poll) {
std::lock_guard<std::mutex> lock(lock_);
auto context_id = GetContextId(guest_ptr); auto context_id = GetContextId(guest_ptr);
assert_true(context_id >= 0); assert_true(context_id >= 0);
@ -283,5 +291,23 @@ void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) {
} }
} }
void XmaDecoder::Pause() {
if (paused_) {
return;
}
paused_ = true;
pause_fence_.Wait();
}
void XmaDecoder::Resume() {
if (!paused_) {
return;
}
paused_ = false;
resume_fence_.Signal();
}
} // namespace apu } // namespace apu
} // namespace xe } // namespace xe

View File

@ -15,6 +15,7 @@
#include <queue> #include <queue>
#include "xenia/apu/xma_context.h" #include "xenia/apu/xma_context.h"
#include "xenia/base/bit_map.h"
#include "xenia/kernel/xthread.h" #include "xenia/kernel/xthread.h"
#include "xenia/xbox.h" #include "xenia/xbox.h"
@ -43,6 +44,10 @@ class XmaDecoder {
uint32_t ReadRegister(uint32_t addr); uint32_t ReadRegister(uint32_t addr);
void WriteRegister(uint32_t addr, uint32_t value); void WriteRegister(uint32_t addr, uint32_t value);
bool is_paused() const { return paused_; }
void Pause();
void Resume();
protected: protected:
int GetContextId(uint32_t guest_ptr); int GetContextId(uint32_t guest_ptr);
@ -66,7 +71,9 @@ class XmaDecoder {
kernel::object_ref<kernel::XHostThread> worker_thread_; kernel::object_ref<kernel::XHostThread> worker_thread_;
xe::threading::Fence worker_fence_; xe::threading::Fence worker_fence_;
std::mutex lock_; bool paused_ = false;
xe::threading::Fence pause_fence_; // Signaled when worker paused.
xe::threading::Fence resume_fence_; // Signaled when resume requested.
// Stored little endian, accessed through 0x7FEA.... // Stored little endian, accessed through 0x7FEA....
union { union {
@ -91,6 +98,7 @@ class XmaDecoder {
static const uint32_t kContextCount = 320; static const uint32_t kContextCount = 320;
XmaContext contexts_[kContextCount]; XmaContext contexts_[kContextCount];
BitMap context_bitmap_;
uint32_t context_data_first_ptr_ = 0; uint32_t context_data_first_ptr_ = 0;
uint32_t context_data_last_ptr_ = 0; uint32_t context_data_last_ptr_ = 0;