[Qt] Initial Qt window initialization

This commit is contained in:
Dr. Chat 2018-05-14 14:09:13 -05:00
parent 76fb04eaf3
commit 99d6788b2c
20 changed files with 97 additions and 161 deletions

View File

@ -10,6 +10,7 @@
#include <gflags/gflags.h>
#include "xenia/app/emulator_window.h"
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
#include "xenia/ui/vulkan/vulkan_instance.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
@ -29,8 +30,28 @@ namespace app {
EmulatorWindow::EmulatorWindow() {}
bool EmulatorWindow::Setup() {
// TODO(DrChat): We own xe::Emulator. Create it and set it up.
return false;
// TODO(DrChat): Pass in command line arguments.
emulator_ = std::make_unique<xe::Emulator>(L"");
// Initialize the graphics backend.
// TODO(DrChat): Pick from gpu command line flag.
if (!InitializeVulkan()) {
return false;
}
auto graphics_factory = [&](cpu::Processor* processor,
kernel::KernelState* kernel_state) {
auto graphics = std::make_unique<gpu::vulkan::VulkanGraphicsSystem>();
if (graphics->Setup(processor, kernel_state,
graphics_provider_->CreateOffscreenContext())) {
return std::unique_ptr<gpu::vulkan::VulkanGraphicsSystem>(nullptr);
}
return graphics;
};
X_STATUS result = emulator_->Setup(nullptr, graphics_factory, nullptr);
return result == X_STATUS_SUCCESS;
}
bool EmulatorWindow::InitializeVulkan() {

View File

@ -38,7 +38,7 @@ class EmulatorWindow : public QMainWindow {
private:
void CreateMenuBar();
std::unique_ptr<xe::Emulator*> emulator_;
std::unique_ptr<xe::Emulator> emulator_;
std::unique_ptr<QWindow> graphics_window_;
std::unique_ptr<ui::GraphicsProvider> graphics_provider_;

View File

@ -75,8 +75,10 @@ class Logger {
~Logger() {
running_ = false;
xe::threading::Wait(write_thread_.get(), true);
fflush(file_);
fclose(file_);
if (file_) {
fflush(file_);
fclose(file_);
}
}
void AppendLine(uint32_t thread_id, LogLevel level, const char prefix_char,
@ -92,8 +94,8 @@ class Logger {
line.prefix_char = prefix_char;
// First, run a check and see if we can increment write
// head without any problems. If so, cmpxchg it to reserve some space in the
// ring. If someone beats us, loop around.
// head without any problems. If so, cmpxchg it to reserve some space in
// the ring. If someone beats us, loop around.
//
// Once we have a reservation, write our data and then increment the write
// tail.
@ -184,8 +186,8 @@ class Logger {
line.thread_id);
Write(prefix, sizeof(prefix) - 1);
if (line.buffer_length) {
// Get access to the line data - which may be split in the ring buffer
// - and write it out in parts.
// Get access to the line data - which may be split in the ring
// buffer - and write it out in parts.
auto line_range = rb.BeginRead(line.buffer_length);
Write(reinterpret_cast<const char*>(line_range.first),
line_range.first_length);

View File

@ -105,8 +105,9 @@ bool DebugWindow::Initialize() {
window_->Resize(1500, 1000);
// Create the graphics context used for drawing.
auto provider = emulator_->display_window()->context()->provider();
window_->set_context(provider->CreateContext(window_.get()));
// TODO(DrChat): Refactor this.
// auto provider = emulator_->display_window()->context()->provider();
// window_->set_context(provider->CreateContext(window_.get()));
// Enable imgui input.
window_->set_imgui_input_enabled(true);

View File

@ -77,17 +77,15 @@ Emulator::~Emulator() {
}
X_STATUS Emulator::Setup(
ui::Window* display_window,
std::function<std::unique_ptr<apu::AudioSystem>(cpu::Processor*)>
audio_system_factory,
std::function<std::unique_ptr<gpu::GraphicsSystem>()>
std::function<std::unique_ptr<gpu::GraphicsSystem>(cpu::Processor*,
kernel::KernelState*)>
graphics_system_factory,
std::function<std::vector<std::unique_ptr<hid::InputDriver>>(ui::Window*)>
std::function<std::vector<std::unique_ptr<hid::InputDriver>>()>
input_driver_factory) {
X_STATUS result = X_STATUS_UNSUCCESSFUL;
display_window_ = display_window;
// Initialize clock.
// 360 uses a 50MHz clock.
Clock::set_guest_tick_frequency(50000000);
@ -132,27 +130,34 @@ X_STATUS Emulator::Setup(
return X_STATUS_UNSUCCESSFUL;
}
// Bring up the virtual filesystem used by the kernel.
file_system_ = std::make_unique<xe::vfs::VirtualFileSystem>();
// Shared kernel state.
kernel_state_ = std::make_unique<xe::kernel::KernelState>(this);
// Initialize the APU.
if (audio_system_factory) {
audio_system_ = audio_system_factory(processor_.get());
if (!audio_system_) {
return X_STATUS_NOT_IMPLEMENTED;
return X_STATUS_UNSUCCESSFUL;
}
}
// Initialize the GPU.
graphics_system_ = graphics_system_factory();
graphics_system_ =
graphics_system_factory(processor_.get(), kernel_state_.get());
if (!graphics_system_) {
return X_STATUS_NOT_IMPLEMENTED;
return X_STATUS_UNSUCCESSFUL;
}
// Initialize the HID.
input_system_ = std::make_unique<xe::hid::InputSystem>(display_window_);
// Initialize all HID drivers.
input_system_ = std::make_unique<xe::hid::InputSystem>();
if (!input_system_) {
return X_STATUS_NOT_IMPLEMENTED;
}
if (input_driver_factory) {
auto input_drivers = input_driver_factory(display_window_);
auto input_drivers = input_driver_factory();
for (size_t i = 0; i < input_drivers.size(); ++i) {
input_system_->AddDriver(std::move(input_drivers[i]));
}
@ -163,26 +168,6 @@ X_STATUS Emulator::Setup(
return result;
}
// Bring up the virtual filesystem used by the kernel.
file_system_ = std::make_unique<xe::vfs::VirtualFileSystem>();
// Shared kernel state.
kernel_state_ = std::make_unique<xe::kernel::KernelState>(this);
// Setup the core components.
result = graphics_system_->Setup(processor_.get(), kernel_state_.get(),
display_window_);
if (result) {
return result;
}
if (audio_system_) {
result = audio_system_->Setup(kernel_state_.get());
if (result) {
return result;
}
}
// HLE kernel modules.
kernel_state_->LoadKernelModule<kernel::xboxkrnl::XboxkrnlModule>();
kernel_state_->LoadKernelModule<kernel::xam::XamModule>();
@ -191,14 +176,6 @@ X_STATUS Emulator::Setup(
// Initialize emulator fallback exception handling last.
ExceptionHandler::Install(Emulator::ExceptionCallbackThunk, this);
if (display_window_) {
// Finish initializing the display.
display_window_->loop()->PostSynchronous([this]() {
xe::ui::GraphicsContextLock context_lock(display_window_->context());
Profiler::set_window(display_window_);
});
}
return result;
}
@ -536,16 +513,6 @@ bool Emulator::ExceptionCallback(Exception* ex) {
context->v[i].i32[1], context->v[i].i32[2], context->v[i].i32[3]);
}
// Display a dialog telling the user the guest has crashed.
display_window()->loop()->PostSynchronous([&]() {
xe::ui::ImGuiDialog::ShowMessageBox(
display_window(), "Uh-oh!",
"The guest has crashed.\n\n"
""
"Xenia has now paused itself.\n"
"A crash dump has been written into the log.");
});
// Now suspend ourself (we should be a guest thread).
current_thread->Suspend(nullptr);
@ -635,7 +602,7 @@ X_STATUS Emulator::CompleteLaunch(const std::wstring& path,
game_title_ = xe::to_wstring(db.title());
auto icon_block = db.icon();
if (icon_block) {
display_window_->SetIcon(icon_block.buffer, icon_block.size);
// display_window_->SetIcon(icon_block.buffer, icon_block.size);
}
}
}

View File

@ -62,9 +62,6 @@ class Emulator {
// Are we currently running a title?
bool is_title_open() const { return title_id_ != 0; }
// Window used for displaying graphical output.
ui::Window* display_window() const { return display_window_; }
// Guest memory system modelling the RAM (both virtual and physical) of the
// system.
Memory* memory() const { return memory_.get(); }
@ -101,12 +98,12 @@ class Emulator {
// Once this function returns a game can be launched using one of the Launch
// functions.
X_STATUS Setup(
ui::Window* display_window,
std::function<std::unique_ptr<apu::AudioSystem>(cpu::Processor*)>
audio_system_factory,
std::function<std::unique_ptr<gpu::GraphicsSystem>()>
std::function<std::unique_ptr<gpu::GraphicsSystem>(cpu::Processor*,
kernel::KernelState*)>
graphics_system_factory,
std::function<std::vector<std::unique_ptr<hid::InputDriver>>(ui::Window*)>
std::function<std::vector<std::unique_ptr<hid::InputDriver>>()>
input_driver_factory);
// Terminates the currently running title.
@ -156,8 +153,6 @@ class Emulator {
std::wstring command_line_;
std::wstring game_title_;
ui::Window* display_window_;
std::unique_ptr<Memory> memory_;
std::unique_ptr<cpu::Processor> processor_;

View File

@ -46,7 +46,7 @@ CommandProcessor::CommandProcessor(GraphicsSystem* graphics_system,
CommandProcessor::~CommandProcessor() = default;
bool CommandProcessor::Initialize(
std::unique_ptr<xe::ui::GraphicsContext> context) {
std::unique_ptr<ui::GraphicsContext> context) {
context_ = std::move(context);
worker_running_ = true;
@ -231,7 +231,7 @@ bool CommandProcessor::Restore(ByteStream* stream) {
bool CommandProcessor::SetupContext() { return true; }
void CommandProcessor::ShutdownContext() { context_.reset(); }
void CommandProcessor::ShutdownContext() {}
void CommandProcessor::InitializeRingBuffer(uint32_t ptr, uint32_t log2_size) {
read_ptr_index_ = 0;

View File

@ -114,7 +114,7 @@ class CommandProcessor {
Shader* active_vertex_shader() const { return active_vertex_shader_; }
Shader* active_pixel_shader() const { return active_pixel_shader_; }
virtual bool Initialize(std::unique_ptr<xe::ui::GraphicsContext> context);
virtual bool Initialize(std::unique_ptr<ui::GraphicsContext> context);
virtual void Shutdown();
void CallInThread(std::function<void()> fn);
@ -255,7 +255,7 @@ class CommandProcessor {
std::atomic<bool> worker_running_;
kernel::object_ref<kernel::XHostThread> worker_thread_;
std::unique_ptr<xe::ui::GraphicsContext> context_;
std::unique_ptr<ui::GraphicsContext> context_;
SwapMode swap_mode_ = SwapMode::kNormal;
SwapState swap_state_;
std::function<void()> swap_request_handler_;

View File

@ -39,69 +39,22 @@ GraphicsSystem::GraphicsSystem() : vsync_worker_running_(false) {}
GraphicsSystem::~GraphicsSystem() = default;
X_STATUS GraphicsSystem::Setup(cpu::Processor* processor,
kernel::KernelState* kernel_state,
ui::Window* target_window) {
X_STATUS GraphicsSystem::Setup(
cpu::Processor* processor, kernel::KernelState* kernel_state,
std::unique_ptr<ui::GraphicsContext> graphics_context) {
memory_ = processor->memory();
processor_ = processor;
kernel_state_ = kernel_state;
target_window_ = target_window;
// Initialize display and rendering context.
// This must happen on the UI thread.
std::unique_ptr<xe::ui::GraphicsContext> processor_context = nullptr;
if (provider_) {
if (target_window_) {
target_window_->loop()->PostSynchronous([&]() {
// Create the context used for presentation.
assert_null(target_window->context());
target_window_->set_context(provider_->CreateContext(target_window_));
// Setup the context the command processor will do all its drawing in.
// It's shared with the display context so that we can resolve
// framebuffers from it.
processor_context = provider()->CreateOffscreenContext();
});
} else {
processor_context = provider()->CreateOffscreenContext();
}
if (!processor_context) {
xe::FatalError(
"Unable to initialize graphics context. Xenia requires Vulkan "
"support.\n"
"\n"
"Ensure you have the latest drivers for your GPU and "
"that it supports Vulkan.\n"
"\n"
"See http://xenia.jp/faq/ for more information and a list of "
"supported GPUs.");
return X_STATUS_UNSUCCESSFUL;
}
}
// Create command processor. This will spin up a thread to process all
// incoming ringbuffer packets.
command_processor_ = CreateCommandProcessor();
if (!command_processor_->Initialize(std::move(processor_context))) {
if (!command_processor_->Initialize(std::move(graphics_context))) {
XELOGE("Unable to initialize command processor");
return X_STATUS_UNSUCCESSFUL;
}
if (target_window) {
command_processor_->set_swap_request_handler(
[this]() { target_window_->Invalidate(); });
// Watch for paint requests to do our swap.
target_window->on_painting.AddListener(
[this](xe::ui::UIEvent* e) { Swap(e); });
// Watch for context lost events.
target_window->on_context_lost.AddListener(
[this](xe::ui::UIEvent* e) { Reset(); });
} else {
command_processor_->set_swap_request_handler([]() {});
}
command_processor_->set_swap_request_handler([]() {});
// Let the processor know we want register access callbacks.
memory_->AddVirtualMappedRange(

View File

@ -43,7 +43,7 @@ class GraphicsSystem {
virtual X_STATUS Setup(cpu::Processor* processor,
kernel::KernelState* kernel_state,
ui::Window* target_window);
std::unique_ptr<ui::GraphicsContext> graphics_context);
virtual void Shutdown();
virtual void Reset();
@ -91,7 +91,6 @@ class GraphicsSystem {
Memory* memory_ = nullptr;
cpu::Processor* processor_ = nullptr;
kernel::KernelState* kernel_state_ = nullptr;
ui::Window* target_window_ = nullptr;
std::unique_ptr<ui::GraphicsProvider> provider_;
uint32_t interrupt_callback_ = 0;

View File

@ -21,14 +21,10 @@ NullGraphicsSystem::NullGraphicsSystem() {}
NullGraphicsSystem::~NullGraphicsSystem() {}
X_STATUS NullGraphicsSystem::Setup(cpu::Processor* processor,
kernel::KernelState* kernel_state,
ui::Window* target_window) {
// This is a null graphics system, but we still setup vulkan because UI needs
// it through us :|
provider_ = xe::ui::vulkan::VulkanProvider::Create(target_window);
return GraphicsSystem::Setup(processor, kernel_state, target_window);
X_STATUS NullGraphicsSystem::Setup(
cpu::Processor* processor, kernel::KernelState* kernel_state,
std::unique_ptr<ui::GraphicsContext> context) {
return GraphicsSystem::Setup(processor, kernel_state, std::move(context));
}
void NullGraphicsSystem::Shutdown() { GraphicsSystem::Shutdown(); }

View File

@ -27,7 +27,7 @@ class NullGraphicsSystem : public GraphicsSystem {
std::wstring name() const override { return L"null"; }
X_STATUS Setup(cpu::Processor* processor, kernel::KernelState* kernel_state,
ui::Window* target_window) override;
std::unique_ptr<ui::GraphicsContext> context) override;
void Shutdown() override;
private:

View File

@ -104,8 +104,12 @@ int TraceDump::Main(const std::vector<std::wstring>& args) {
bool TraceDump::Setup() {
// Create the emulator but don't initialize so we can setup the window.
emulator_ = std::make_unique<Emulator>(L"");
X_STATUS result = emulator_->Setup(
nullptr, nullptr, [this]() { return CreateGraphicsSystem(); }, nullptr);
X_STATUS result =
emulator_->Setup(nullptr,
[this](cpu::Processor*, kernel::KernelState*) {
return CreateGraphicsSystem();
},
nullptr);
if (XFAILED(result)) {
XELOGE("Failed to setup emulator: %.8X", result);
return false;

View File

@ -124,8 +124,11 @@ bool TraceViewer::Setup() {
// Create the emulator but don't initialize so we can setup the window.
emulator_ = std::make_unique<Emulator>(L"");
X_STATUS result =
emulator_->Setup(window_.get(), nullptr,
[this]() { return CreateGraphicsSystem(); }, nullptr);
emulator_->Setup(nullptr,
[this](cpu::Processor*, kernel::KernelState*) {
return CreateGraphicsSystem();
},
nullptr);
if (XFAILED(result)) {
XELOGE("Failed to setup emulator: %.8X", result);
return false;

View File

@ -60,7 +60,7 @@ bool VulkanCommandProcessor::SetupContext() {
}
// Acquire our device and queue.
auto context = static_cast<xe::ui::vulkan::VulkanContext*>(context_.get());
auto context = static_cast<ui::vulkan::VulkanContext*>(context_.get());
device_ = context->device();
queue_ = device_->AcquireQueue(device_->queue_family_index());
if (!queue_) {

View File

@ -33,24 +33,17 @@ using xe::ui::vulkan::CheckResult;
VulkanGraphicsSystem::VulkanGraphicsSystem() {}
VulkanGraphicsSystem::~VulkanGraphicsSystem() = default;
X_STATUS VulkanGraphicsSystem::Setup(cpu::Processor* processor,
kernel::KernelState* kernel_state,
ui::Window* target_window) {
// Must create the provider so we can create contexts.
auto provider = xe::ui::vulkan::VulkanProvider::Create(target_window);
device_ = provider->device();
provider_ = std::move(provider);
X_STATUS VulkanGraphicsSystem::Setup(
cpu::Processor* processor, kernel::KernelState* kernel_state,
std::unique_ptr<ui::GraphicsContext> context) {
device_ = static_cast<ui::vulkan::VulkanContext*>(context.get())->device();
auto result = GraphicsSystem::Setup(processor, kernel_state, target_window);
auto result =
GraphicsSystem::Setup(processor, kernel_state, std::move(context));
if (result) {
return result;
}
if (target_window) {
display_context_ = reinterpret_cast<xe::ui::vulkan::VulkanContext*>(
target_window->context());
}
// Create our own command pool we can use for captures.
VkCommandPoolCreateInfo create_info = {
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,

View File

@ -27,7 +27,7 @@ class VulkanGraphicsSystem : public GraphicsSystem {
std::wstring name() const override { return L"Vulkan"; }
X_STATUS Setup(cpu::Processor* processor, kernel::KernelState* kernel_state,
ui::Window* target_window) override;
std::unique_ptr<ui::GraphicsContext> context) override;
void Shutdown() override;
std::unique_ptr<xe::ui::RawImage> Capture() override;

View File

@ -16,7 +16,7 @@
namespace xe {
namespace hid {
InputSystem::InputSystem(xe::ui::Window* window) : window_(window) {}
InputSystem::InputSystem() {}
InputSystem::~InputSystem() = default;

View File

@ -28,11 +28,9 @@ namespace hid {
class InputSystem {
public:
explicit InputSystem(xe::ui::Window* window);
explicit InputSystem();
~InputSystem();
xe::ui::Window* window() const { return window_; }
X_STATUS Setup();
void AddDriver(std::unique_ptr<InputDriver> driver);
@ -45,8 +43,6 @@ class InputSystem {
X_INPUT_KEYSTROKE* out_keystroke);
private:
xe::ui::Window* window_ = nullptr;
std::vector<std::unique_ptr<InputDriver>> drivers_;
};

View File

@ -130,6 +130,7 @@ SHIM_CALL XamShowMessageBoxUI_shim(PPCContext* ppc_context,
// Auto-pick the focused button.
chosen_button = active_button;
} else {
/*
auto display_window = kernel_state->emulator()->display_window();
xe::threading::Fence fence;
display_window->loop()->PostSynchronous([&]() {
@ -155,6 +156,7 @@ SHIM_CALL XamShowMessageBoxUI_shim(PPCContext* ppc_context,
++xam_dialogs_shown_;
fence.Wait();
--xam_dialogs_shown_;
*/
}
SHIM_SET_MEM_32(result_ptr, chosen_button);
@ -258,6 +260,7 @@ dword_result_t XamShowKeyboardUI(dword_t user_index, dword_t flags,
std::wstring out_text;
/*
auto display_window = kernel_state()->emulator()->display_window();
xe::threading::Fence fence;
display_window->loop()->PostSynchronous([&]() {
@ -270,6 +273,7 @@ dword_result_t XamShowKeyboardUI(dword_t user_index, dword_t flags,
++xam_dialogs_shown_;
fence.Wait();
--xam_dialogs_shown_;
*/
// Zero the output buffer.
std::memset(buffer, 0, buffer_length * 2);
@ -330,6 +334,7 @@ SHIM_CALL XamShowDirtyDiscErrorUI_shim(PPCContext* ppc_context,
return;
}
/*
auto display_window = kernel_state->emulator()->display_window();
xe::threading::Fence fence;
display_window->loop()->PostSynchronous([&]() {
@ -342,6 +347,7 @@ SHIM_CALL XamShowDirtyDiscErrorUI_shim(PPCContext* ppc_context,
++xam_dialogs_shown_;
fence.Wait();
--xam_dialogs_shown_;
*/
// This is death, and should never return.
// TODO(benvanik): cleaner exit.