XMA: Add an idle "low-power" state for the decoder.
This commit is contained in:
parent
c5487371f9
commit
a093fdcef8
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue