[UI] Image post-processing and full presentation/window rework
[GPU] Add FXAA post-processing [UI] Add FidelityFX FSR and CAS post-processing [UI] Add blue noise dithering from 10bpc to 8bpc [GPU] Apply the DC PWL gamma ramp closer to the spec, supporting fully white color [UI] Allow the GPU CP thread to present on the host directly, bypassing the UI thread OS paint event [UI] Allow variable refresh rate (or tearing) [UI] Present the newest frame (restart) on DXGI [UI] Replace GraphicsContext with a far more advanced Presenter with more coherent surface connection and UI overlay state management [UI] Connect presentation to windows via the Surface class, not native window handles [Vulkan] Switch to simpler Vulkan setup with no instance/device separation due to interdependencies and to pass fewer objects around [Vulkan] Lower the minimum required Vulkan version to 1.0 [UI/GPU] Various cleanup, mainly ComPtr usage [UI] Support per-monitor DPI awareness v2 on Windows [UI] DPI-scale Dear ImGui [UI] Replace the remaining non-detachable window delegates with unified window event and input listeners [UI] Allow listeners to safely destroy or close the window, and to register/unregister listeners without use-after-free and the ABA problem [UI] Explicit Z ordering of input listeners and UI overlays, top-down for input, bottom-up for drawing [UI] Add explicit window lifecycle phases [UI] Replace Window virtual functions with explicit desired state, its application, actual state, its feedback [UI] GTK: Apply the initial size to the drawing area [UI] Limit internal UI frame rate to that of the monitor [UI] Hide the cursor using a timer instead of polling due to no repeated UI thread paints with GPU CP thread presentation, and only within the window
This commit is contained in:
@@ -10,9 +10,12 @@
|
||||
#ifndef XENIA_EMULATOR_H_
|
||||
#define XENIA_EMULATOR_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/delegate.h"
|
||||
#include "xenia/base/exception_handler.h"
|
||||
@@ -38,6 +41,7 @@ class InputDriver;
|
||||
class InputSystem;
|
||||
} // namespace hid
|
||||
namespace ui {
|
||||
class ImGuiDrawer;
|
||||
class Window;
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
@@ -50,6 +54,37 @@ constexpr fourcc_t kEmulatorSaveSignature = make_fourcc("XSAV");
|
||||
// This is responsible for initializing and managing all the various subsystems.
|
||||
class Emulator {
|
||||
public:
|
||||
// This is the class for the top-level callbacks. They may be called in an
|
||||
// undefined order, so among them there must be no dependencies on each other,
|
||||
// especially hierarchical ones. If hierarchical handling is needed, for
|
||||
// instance, if a specific implementation of a subsystem needs to handle
|
||||
// changes, but the entire implementation must be reloaded, the implementation
|
||||
// in this example _must not_ register / unregister its own callback - rather,
|
||||
// the proper ordering and hierarchy should be constructed in a single
|
||||
// callback (in this example, for the whole subsystem).
|
||||
//
|
||||
// All callbacks must be created and destroyed in the UI thread only (or the
|
||||
// thread that takes its place in the architecture of the specific app if
|
||||
// there's no UI), as they are invoked in the UI thread.
|
||||
class GameConfigLoadCallback {
|
||||
public:
|
||||
GameConfigLoadCallback(Emulator& emulator);
|
||||
GameConfigLoadCallback(const GameConfigLoadCallback& callback) = delete;
|
||||
GameConfigLoadCallback& operator=(const GameConfigLoadCallback& callback) =
|
||||
delete;
|
||||
virtual ~GameConfigLoadCallback();
|
||||
|
||||
// The callback is invoked in the UI thread (or the thread that takes its
|
||||
// place in the architecture of the specific app if there's no UI).
|
||||
virtual void PostGameConfigLoad() = 0;
|
||||
|
||||
protected:
|
||||
Emulator& emulator() const { return emulator_; }
|
||||
|
||||
private:
|
||||
Emulator& emulator_;
|
||||
};
|
||||
|
||||
explicit Emulator(const std::filesystem::path& command_line,
|
||||
const std::filesystem::path& storage_root,
|
||||
const std::filesystem::path& content_root,
|
||||
@@ -82,9 +117,13 @@ class Emulator {
|
||||
// Are we currently running a title?
|
||||
bool is_title_open() const { return title_id_.has_value(); }
|
||||
|
||||
// Window used for displaying graphical output.
|
||||
// Window used for displaying graphical output. Can be null.
|
||||
ui::Window* display_window() const { return display_window_; }
|
||||
|
||||
// ImGui drawer for various kinds of dialogs requested by the guest. Can be
|
||||
// null.
|
||||
ui::ImGuiDrawer* imgui_drawer() const { return imgui_drawer_; }
|
||||
|
||||
// Guest memory system modelling the RAM (both virtual and physical) of the
|
||||
// system.
|
||||
Memory* memory() const { return memory_.get(); }
|
||||
@@ -121,7 +160,7 @@ class Emulator {
|
||||
// Once this function returns a game can be launched using one of the Launch
|
||||
// functions.
|
||||
X_STATUS Setup(
|
||||
ui::Window* display_window,
|
||||
ui::Window* display_window, ui::ImGuiDrawer* imgui_drawer,
|
||||
std::function<std::unique_ptr<apu::AudioSystem>(cpu::Processor*)>
|
||||
audio_system_factory,
|
||||
std::function<std::unique_ptr<gpu::GraphicsSystem>()>
|
||||
@@ -170,6 +209,9 @@ class Emulator {
|
||||
static bool ExceptionCallbackThunk(Exception* ex, void* data);
|
||||
bool ExceptionCallback(Exception* ex);
|
||||
|
||||
void AddGameConfigLoadCallback(GameConfigLoadCallback* callback);
|
||||
void RemoveGameConfigLoadCallback(GameConfigLoadCallback* callback);
|
||||
|
||||
std::string FindLaunchModule();
|
||||
|
||||
X_STATUS CompleteLaunch(const std::filesystem::path& path,
|
||||
@@ -183,7 +225,8 @@ class Emulator {
|
||||
std::string title_name_;
|
||||
std::string title_version_;
|
||||
|
||||
ui::Window* display_window_;
|
||||
ui::Window* display_window_ = nullptr;
|
||||
ui::ImGuiDrawer* imgui_drawer_ = nullptr;
|
||||
|
||||
std::unique_ptr<Memory> memory_;
|
||||
|
||||
@@ -196,6 +239,16 @@ class Emulator {
|
||||
std::unique_ptr<vfs::VirtualFileSystem> file_system_;
|
||||
|
||||
std::unique_ptr<kernel::KernelState> kernel_state_;
|
||||
|
||||
// Accessible only from the thread that invokes those callbacks (the UI thread
|
||||
// if the UI is available).
|
||||
std::vector<GameConfigLoadCallback*> game_config_load_callbacks_;
|
||||
// Using an index, not an iterator, because after the erasure, the adjustment
|
||||
// must be done for the vector element indices that would be in the iterator
|
||||
// range that would be invalidated.
|
||||
// SIZE_MAX if not currently in the game config load callback loop.
|
||||
size_t game_config_load_callback_loop_next_index_ = SIZE_MAX;
|
||||
|
||||
kernel::object_ref<kernel::XThread> main_thread_;
|
||||
std::optional<uint32_t> title_id_; // Currently running title ID
|
||||
|
||||
|
||||
Reference in New Issue
Block a user