XMA: Add an idle "low-power" state for the decoder.

This commit is contained in:
Dr. Chat 2017-01-28 20:58:23 -06:00
parent c5487371f9
commit a093fdcef8
4 changed files with 28 additions and 9 deletions

View File

@ -98,10 +98,10 @@ int XmaContext::Setup(uint32_t id, Memory* memory, uint32_t guest_ptr) {
return 0;
}
void XmaContext::Work() {
bool XmaContext::Work() {
std::lock_guard<std::mutex> lock(lock_);
if (!is_allocated() || !is_enabled()) {
return;
return false;
}
set_is_enabled(false);
@ -110,6 +110,7 @@ void XmaContext::Work() {
XMA_CONTEXT_DATA data(context_ptr);
DecodePackets(&data);
data.Store(context_ptr);
return true;
}
void XmaContext::Enable() {

View File

@ -147,7 +147,7 @@ class XmaContext {
~XmaContext();
int Setup(uint32_t id, Memory* memory, uint32_t guest_ptr);
void Work();
bool Work();
void Enable();
bool Block(bool poll);

View File

@ -118,6 +118,7 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
context_bitmap_.Resize(kContextCount);
worker_running_ = true;
work_event_ = xe::threading::Event::CreateAutoResetEvent(false);
worker_thread_ = kernel::object_ref<kernel::XHostThread>(
new kernel::XHostThread(kernel_state, 128 * 1024, 0, [this]() {
WorkerThreadMain();
@ -131,11 +132,13 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
}
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++) {
XmaContext& context = contexts_[n];
context.Work();
did_work = context.Work() || did_work;
// TODO: Need thread safety to do this.
// Probably not too important though.
@ -148,19 +151,34 @@ void XmaDecoder::WorkerThreadMain() {
resume_fence_.Wait();
}
if (!did_work) {
idle_loop_count++;
} else {
idle_loop_count = 0;
}
if (idle_loop_count > 500) {
// Idle for an extended period. Introduce a 20ms wait.
xe::threading::Wait(work_event_.get(), false,
std::chrono::milliseconds(20));
}
xe::threading::MaybeYield();
}
}
void XmaDecoder::Shutdown() {
worker_running_ = false;
worker_fence_.Signal();
worker_thread_.reset();
work_event_->Set();
if (paused_) {
Resume();
}
// Wait for work thread.
xe::threading::Wait(worker_thread_->thread(), false);
worker_thread_.reset();
memory()->SystemHeapFree(registers_.context_array_ptr);
}
@ -261,7 +279,7 @@ void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) {
}
// Signal the decoder thread to start processing.
worker_fence_.Signal();
work_event_->Set();
} else if (r >= 0x1A40 && r <= 0x1A40 + 9 * 4) {
// Context lock command.
// This requests a lock by flagging the context.
@ -276,7 +294,7 @@ void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) {
}
// Signal the decoder thread to start processing.
worker_fence_.Signal();
work_event_->Set();
} else if (r >= 0x1A80 && r <= 0x1A80 + 9 * 4) {
// Context clear command.
// This will reset the given hardware contexts.

View File

@ -69,7 +69,7 @@ class XmaDecoder {
std::atomic<bool> worker_running_ = {false};
kernel::object_ref<kernel::XHostThread> worker_thread_;
xe::threading::Fence worker_fence_;
std::unique_ptr<xe::threading::Event> work_event_ = nullptr;
bool paused_ = false;
xe::threading::Fence pause_fence_; // Signaled when worker paused.