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;
|
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() {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue