[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:
Triang3l
2022-01-29 13:22:03 +03:00
parent 372bdd3ec9
commit fe3f0f26e4
428 changed files with 75942 additions and 18360 deletions

View File

@@ -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