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; return 0;
} }
void XmaContext::Work() { bool XmaContext::Work() {
std::lock_guard<std::mutex> lock(lock_); std::lock_guard<std::mutex> lock(lock_);
if (!is_allocated() || !is_enabled()) { if (!is_allocated() || !is_enabled()) {
return; return false;
} }
set_is_enabled(false); set_is_enabled(false);
@ -110,6 +110,7 @@ void XmaContext::Work() {
XMA_CONTEXT_DATA data(context_ptr); XMA_CONTEXT_DATA data(context_ptr);
DecodePackets(&data); DecodePackets(&data);
data.Store(context_ptr); data.Store(context_ptr);
return true;
} }
void XmaContext::Enable() { void XmaContext::Enable() {

View File

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

View File

@ -118,6 +118,7 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
context_bitmap_.Resize(kContextCount); context_bitmap_.Resize(kContextCount);
worker_running_ = true; worker_running_ = true;
work_event_ = xe::threading::Event::CreateAutoResetEvent(false);
worker_thread_ = kernel::object_ref<kernel::XHostThread>( worker_thread_ = kernel::object_ref<kernel::XHostThread>(
new kernel::XHostThread(kernel_state, 128 * 1024, 0, [this]() { new kernel::XHostThread(kernel_state, 128 * 1024, 0, [this]() {
WorkerThreadMain(); WorkerThreadMain();
@ -131,11 +132,13 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
} }
void XmaDecoder::WorkerThreadMain() { void XmaDecoder::WorkerThreadMain() {
uint32_t idle_loop_count = 0;
while (worker_running_) { while (worker_running_) {
// Okay, let's loop through XMA contexts to find ones we need to decode! // 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++) { for (uint32_t n = 0; n < kContextCount; n++) {
XmaContext& context = contexts_[n]; XmaContext& context = contexts_[n];
context.Work(); did_work = context.Work() || did_work;
// TODO: Need thread safety to do this. // TODO: Need thread safety to do this.
// Probably not too important though. // Probably not too important though.
@ -148,19 +151,34 @@ void XmaDecoder::WorkerThreadMain() {
resume_fence_.Wait(); 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(); xe::threading::MaybeYield();
} }
} }
void XmaDecoder::Shutdown() { void XmaDecoder::Shutdown() {
worker_running_ = false; worker_running_ = false;
worker_fence_.Signal(); work_event_->Set();
worker_thread_.reset();
if (paused_) { if (paused_) {
Resume(); Resume();
} }
// Wait for work thread.
xe::threading::Wait(worker_thread_->thread(), false);
worker_thread_.reset();
memory()->SystemHeapFree(registers_.context_array_ptr); 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. // Signal the decoder thread to start processing.
worker_fence_.Signal(); work_event_->Set();
} else if (r >= 0x1A40 && r <= 0x1A40 + 9 * 4) { } else if (r >= 0x1A40 && r <= 0x1A40 + 9 * 4) {
// Context lock command. // Context lock command.
// This requests a lock by flagging the context. // 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. // Signal the decoder thread to start processing.
worker_fence_.Signal(); work_event_->Set();
} else if (r >= 0x1A80 && r <= 0x1A80 + 9 * 4) { } else if (r >= 0x1A80 && r <= 0x1A80 + 9 * 4) {
// Context clear command. // Context clear command.
// This will reset the given hardware contexts. // This will reset the given hardware contexts.

View File

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