This seems to dramatically improve most games (especially with --vsync=false), though it may cause swap issues with others. New code should be easier to port, and enables elemental-forms to be drawn for any emulator UI.
83 lines
2.4 KiB
C++
83 lines
2.4 KiB
C++
/**
|
|
******************************************************************************
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
******************************************************************************
|
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include "xenia/ui/loop.h"
|
|
|
|
#include "el/message_handler.h"
|
|
#include "el/util/metrics.h"
|
|
#include "el/util/timer.h"
|
|
#include "xenia/base/assert.h"
|
|
#include "xenia/base/threading.h"
|
|
|
|
namespace xe {
|
|
namespace ui {
|
|
|
|
// The loop designated as being the main loop elemental-forms will use for all
|
|
// activity.
|
|
// TODO(benvanik): refactor elemental-forms to now need a global.
|
|
Loop* elemental_loop_ = nullptr;
|
|
|
|
Loop* Loop::elemental_loop() { return elemental_loop_; }
|
|
|
|
void Loop::set_elemental_loop(Loop* loop) {
|
|
assert_null(elemental_loop_);
|
|
elemental_loop_ = loop;
|
|
}
|
|
|
|
Loop::Loop() = default;
|
|
|
|
Loop::~Loop() {
|
|
if (this == elemental_loop_) {
|
|
elemental_loop_ = nullptr;
|
|
}
|
|
}
|
|
|
|
void Loop::PostSynchronous(std::function<void()> fn) {
|
|
xe::threading::Fence fence;
|
|
Post([&fn, &fence]() {
|
|
fn();
|
|
fence.Signal();
|
|
});
|
|
fence.Wait();
|
|
}
|
|
|
|
} // namespace ui
|
|
} // namespace xe
|
|
|
|
void el::util::RescheduleTimer(uint64_t fire_time) {
|
|
assert_not_null(xe::ui::elemental_loop_);
|
|
if (fire_time == el::MessageHandler::kNotSoon) {
|
|
return;
|
|
}
|
|
|
|
uint64_t now = el::util::GetTimeMS();
|
|
uint64_t delay_millis = fire_time >= now ? fire_time - now : 0;
|
|
xe::ui::elemental_loop_->PostDelayed([]() {
|
|
uint64_t next_fire_time = el::MessageHandler::GetNextMessageFireTime();
|
|
uint64_t now = el::util::GetTimeMS();
|
|
if (now < next_fire_time) {
|
|
// We timed out *before* we were supposed to (the OS is not playing
|
|
// nice).
|
|
// Calling ProcessMessages now won't achieve a thing so force a
|
|
// reschedule
|
|
// of the platform timer again with the same time.
|
|
// ReschedulePlatformTimer(next_fire_time, true);
|
|
return;
|
|
}
|
|
|
|
el::MessageHandler::ProcessMessages();
|
|
|
|
// If we still have things to do (because we didn't process all
|
|
// messages,
|
|
// or because there are new messages), we need to rescedule, so call
|
|
// RescheduleTimer.
|
|
el::util::RescheduleTimer(el::MessageHandler::GetNextMessageFireTime());
|
|
}, delay_millis);
|
|
}
|