[App/Qt] Initial GraphicsWindow work

This code does not work at all and needs a major refactoring
This commit is contained in:
Satori 2020-08-26 15:53:15 +01:00
parent 72ae10dc2b
commit c22d27d901
7 changed files with 301 additions and 167 deletions

View File

@ -11,22 +11,29 @@
#include <QVulkanWindow> #include <QVulkanWindow>
#include "emulator_window.h"
#include "third_party/imgui/imgui.h" #include "third_party/imgui/imgui.h"
#include "xenia/apu/nop/nop_audio_system.h"
#include "xenia/apu/sdl/sdl_audio_system.h"
#include "xenia/apu/xaudio2/xaudio2_audio_system.h" #include "xenia/apu/xaudio2/xaudio2_audio_system.h"
#include "xenia/base/clock.h"
#include "xenia/base/cvar.h" #include "xenia/base/cvar.h"
#include "xenia/base/debugging.h" #include "xenia/base/debugging.h"
#include "xenia/base/factory.h"
#include "xenia/base/logging.h" #include "xenia/base/logging.h"
#include "xenia/base/platform.h" #include "xenia/base/platform.h"
#include "xenia/base/profiling.h" #include "xenia/base/profiling.h"
#include "xenia/base/threading.h" #include "xenia/base/threading.h"
#include "xenia/emulator.h" #include "xenia/emulator.h"
#include "xenia/gpu/command_processor.h"
#include "xenia/gpu/d3d12/d3d12_graphics_system.h"
#include "xenia/gpu/graphics_system.h" #include "xenia/gpu/graphics_system.h"
#include "xenia/gpu/null/null_graphics_system.h"
#include "xenia/gpu/vulkan/vulkan_graphics_system.h" #include "xenia/gpu/vulkan/vulkan_graphics_system.h"
#include "xenia/hid/input_system.h" #include "xenia/hid/input_system.h"
#include "xenia/hid/nop/nop_hid.h"
#include "xenia/hid/sdl/sdl_hid.h"
#include "xenia/hid/winkey/winkey_hid.h"
#include "xenia/hid/xinput/xinput_hid.h" #include "xenia/hid/xinput/xinput_hid.h"
#include "xenia/ui/vulkan/vulkan_instance.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
DEFINE_string(apu, "any", "Audio system. Use: [any, nop, xaudio2]", "General"); DEFINE_string(apu, "any", "Audio system. Use: [any, nop, xaudio2]", "General");
DEFINE_string(gpu, "any", "Graphics system. Use: [any, vulkan, null]", DEFINE_string(gpu, "any", "Graphics system. Use: [any, vulkan, null]",
@ -41,158 +48,97 @@ DEFINE_bool(fullscreen, false, "Toggles fullscreen", "General");
namespace xe { namespace xe {
namespace app { namespace app {
class VulkanWindow : public QVulkanWindow { std::unique_ptr<apu::AudioSystem> CreateAudioSystem(cpu::Processor* processor) {
public: Factory<apu::AudioSystem, cpu::Processor*> factory;
VulkanWindow(gpu::vulkan::VulkanGraphicsSystem* gfx) #if XE_PLATFORM_WIN32
: graphics_system_(gfx) {} factory.Add<apu::xaudio2::XAudio2AudioSystem>("xaudio2");
QVulkanWindowRenderer* createRenderer() override; #endif // XE_PLATFORM_WIN32
factory.Add<apu::sdl::SDLAudioSystem>("sdl");
factory.Add<apu::nop::NopAudioSystem>("nop");
return factory.Create(cvars::apu, processor);
}
private: std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() {
gpu::vulkan::VulkanGraphicsSystem* graphics_system_; Factory<gpu::GraphicsSystem> factory;
}; #if XE_PLATFORM_WIN32
factory.Add<gpu::d3d12::D3D12GraphicsSystem>("d3d12");
#endif // XE_PLATFORM_WIN32
factory.Add<gpu::vulkan::VulkanGraphicsSystem>("vulkan");
factory.Add<gpu::null::NullGraphicsSystem>("null");
return factory.Create(cvars::gpu);
}
class VulkanRenderer : public QVulkanWindowRenderer { std::vector<std::unique_ptr<hid::InputDriver>> CreateInputDrivers(
public: ui::Window* window) {
VulkanRenderer(VulkanWindow* window, std::vector<std::unique_ptr<hid::InputDriver>> drivers;
gpu::vulkan::VulkanGraphicsSystem* graphics_system) if (cvars::hid.compare("nop") == 0) {
: window_(window), graphics_system_(graphics_system) {} drivers.emplace_back(hid::nop::Create(window));
} else {
void startNextFrame() override { Factory<hid::InputDriver, ui::Window*> factory;
// Copy the graphics frontbuffer to our backbuffer. #if XE_PLATFORM_WIN32
//auto swap_state = graphics_system_->swap_state(); factory.Add("xinput", hid::xinput::Create);
// WinKey input driver should always be the last input driver added!
auto cmd = window_->currentCommandBuffer(); factory.Add("winkey", hid::winkey::Create);
//auto src = reinterpret_cast<VkImage>( #endif // XE_PLATFORM_WIN32
// swap_state->buffer_textures[swap_state->current_buffer]); factory.Add("sdl", hid::sdl::Create);
auto dest = window_->swapChainImage(window_->currentSwapChainImageIndex()); for (auto& driver : factory.CreateAll(cvars::hid, window)) {
auto dest_size = window_->swapChainImageSize(); if (XSUCCEEDED(driver->Setup())) {
drivers.emplace_back(std::move(driver));
VkImageMemoryBarrier barrier; }
std::memset(&barrier, 0, sizeof(VkImageMemoryBarrier)); }
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; if (drivers.empty()) {
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; // Fallback to nop if none created.
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; drivers.emplace_back(xe::hid::nop::Create(window));
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; }
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
//barrier.image = src;
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0,
nullptr, 1, &barrier);
VkImageBlit region;
region.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
region.srcOffsets[0] = {0, 0, 0};
/*region.srcOffsets[1] = {static_cast<int32_t>(swap_state->width),
static_cast<int32_t>(swap_state->height), 1};*/
region.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
region.dstOffsets[0] = {0, 0, 0};
region.dstOffsets[1] = {static_cast<int32_t>(dest_size.width()),
static_cast<int32_t>(dest_size.height()), 1};
/* vkCmdBlitImage(cmd, src, VK_IMAGE_LAYOUT_GENERAL, dest,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region,
VK_FILTER_LINEAR);*/
//swap_state->pending = false;
window_->frameReady();
} }
return drivers;
private:
gpu::vulkan::VulkanGraphicsSystem* graphics_system_;
VulkanWindow* window_;
};
QVulkanWindowRenderer* VulkanWindow::createRenderer() {
return new VulkanRenderer(this, graphics_system_);
} }
EmulatorWindow::EmulatorWindow(Loop* loop, const std::string& title) EmulatorWindow::EmulatorWindow(Loop* loop, const std::string& title)
: QtWindow(loop, title) { : QtWindow(loop, title) {
// TODO(DrChat): Pass in command line arguments. // TODO(DrChat): Pass in command line arguments.
emulator_ = std::make_unique<xe::Emulator>("","",""); emulator_ = std::make_unique<xe::Emulator>("", "", "");
auto audio_factory = [&](cpu::Processor* processor, X_STATUS result = emulator_->Setup(this, CreateAudioSystem,
kernel::KernelState* kernel_state) { CreateGraphicsSystem, CreateInputDrivers);
auto audio = apu::xaudio2::XAudio2AudioSystem::Create(processor); if (result == X_STATUS_SUCCESS) {
if (audio->Setup(kernel_state) != X_STATUS_SUCCESS) { // Setup a callback called when the emulator wants to swap.
audio->Shutdown(); emulator_->graphics_system()->command_processor()->set_swap_request_handler(
return std::unique_ptr<apu::AudioSystem>(nullptr); [&]() {
} auto graphics_window =
reinterpret_cast<QWindow*>(this->graphics_window_.get());
return audio; QMetaObject::invokeMethod(graphics_window, "requestUpdate",
}; Qt::QueuedConnection);
});
graphics_provider_ = ui::vulkan::VulkanProvider::Create(nullptr);
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()->target_window())) {
graphics->Shutdown();
return std::unique_ptr<gpu::vulkan::VulkanGraphicsSystem>(nullptr);
}
return graphics;
};
auto input_factory = [&](ui::Window* window) {
std::vector<std::unique_ptr<hid::InputDriver>> drivers;
auto xinput_driver = hid::xinput::Create(window);
xinput_driver->Setup();
drivers.push_back(std::move(xinput_driver));
return drivers;
};
//X_STATUS result = emulator_->Setup(this, audio_factory, graphics_factory, input_factory);
//if (result == X_STATUS_SUCCESS) {
// // Setup a callback called when the emulator wants to swap.
// emulator_->graphics_system()->SetSwapCallback([&]() {
// QMetaObject::invokeMethod(this->graphics_window_.get(), "requestUpdate",
// Qt::QueuedConnection);
// });
//}
//// Initialize our backend display window.
//if (!InitializeVulkan()) {
// return;
//}
//// Set a callback on launch
//emulator_->on_launch.AddListener([this]() {
// auto title_db = this->emulator()->game_data();
// if (title_db) {
// QPixmap p;
// auto icon_block = title_db->icon();
// if (icon_block.buffer &&
// p.loadFromData(icon_block.buffer, uint(icon_block.size), "PNG")) {
// this->setWindowIcon(QIcon(p));
// }
// }
//});
}
bool EmulatorWindow::InitializeVulkan() {
auto provider =
reinterpret_cast<ui::vulkan::VulkanProvider*>(graphics_provider_.get());
// Create a Qt wrapper around our vulkan instance.
vulkan_instance_ = std::make_unique<QVulkanInstance>();
vulkan_instance_->setVkInstance(*provider->instance());
if (!vulkan_instance_->create()) {
return false;
} }
graphics_window_ = std::make_unique<VulkanWindow>( if (!EmulatorWindow::Initialize()) {
reinterpret_cast<gpu::vulkan::VulkanGraphicsSystem*>( return;
emulator_->graphics_system())); }
graphics_window_->setVulkanInstance(vulkan_instance_.get());
// Set a callback on launch
emulator_->on_launch.AddListener(
[this](unsigned int title_id, std ::string_view title) {
auto title_db = this->emulator()->game_data();
if (title_db) {
QPixmap p;
auto icon_block = title_db->icon();
if (icon_block.buffer &&
p.loadFromData(icon_block.buffer, uint(icon_block.size), "PNG")) {
this->setWindowIcon(QIcon(p));
}
}
});
}
bool EmulatorWindow::Initialize() {
if (!graphics_window_->Initialize()) {
XELOGE("Could not initialize graphics window");
return false;
}
// Now set the graphics window as our central widget. // Now set the graphics window as our central widget.
QWidget* wrapper = QWidget::createWindowContainer(graphics_window_.get()); QWidget* wrapper = QWidget::createWindowContainer(
dynamic_cast<QWindow*>(graphics_window_.get()));
setCentralWidget(wrapper); setCentralWidget(wrapper);
return true; return true;

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* Xenia : Xbox 360 Emulator Research Project * * Xenia : Xbox 360 Emulator Research Project *
****************************************************************************** ******************************************************************************
* Copyright 2018 Ben Vanik. All rights reserved. * * Copyright 2020 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. * * Released under the BSD license - see LICENSE in the root for more details. *
****************************************************************************** ******************************************************************************
*/ */
@ -10,15 +10,11 @@
#ifndef XENIA_APP_MAIN_WINDOW_H_ #ifndef XENIA_APP_MAIN_WINDOW_H_
#define XENIA_APP_MAIN_WINDOW_H_ #define XENIA_APP_MAIN_WINDOW_H_
#include <QMainWindow>
#include <QVulkanInstance>
#include <QWindow>
#include "xenia/emulator.h" #include "xenia/emulator.h"
#include "xenia/ui/graphics_context.h" #include "xenia/ui/graphics_context.h"
#include "xenia/ui/graphics_provider.h" #include "xenia/ui/qt/graphics_window.h"
#include "xenia/ui/qt/window_qt.h"
#include "xenia/ui/qt/loop_qt.h" #include "xenia/ui/qt/loop_qt.h"
#include "xenia/ui/qt/window_qt.h"
namespace xe { namespace xe {
namespace app { namespace app {
@ -26,36 +22,28 @@ namespace app {
class VulkanWindow; class VulkanWindow;
class VulkanRenderer; class VulkanRenderer;
using ui::qt::QtWindow;
using ui::Loop; using ui::Loop;
using ui::qt::GraphicsWindow;
using ui::qt::QtWindow;
class EmulatorWindow : public ui::qt::QtWindow { class EmulatorWindow : public QtWindow {
Q_OBJECT Q_OBJECT
public: public:
EmulatorWindow(Loop *loop, const std::string& title); EmulatorWindow(Loop* loop, const std::string& title);
bool Launch(const std::string& path); bool Launch(const std::string& path);
xe::Emulator* emulator() { return emulator_.get(); } Emulator* emulator() const { return emulator_.get(); }
GraphicsWindow* graphics_window() const { return graphics_window_.get(); }
protected: hid::InputSystem* input_system() const { return input_system_.get(); }
// Events
private slots:
private: private:
bool Initialize() override;
void CreateMenuBar(); void CreateMenuBar();
bool InitializeVulkan(); std::unique_ptr<Emulator> emulator_;
std::unique_ptr<GraphicsWindow> graphics_window_;
std::unique_ptr<xe::Emulator> emulator_;
std::unique_ptr<QWindow> graphics_window_;
std::unique_ptr<ui::GraphicsProvider> graphics_provider_;
std::unique_ptr<hid::InputSystem> input_system_; std::unique_ptr<hid::InputSystem> input_system_;
std::unique_ptr<QVulkanInstance> vulkan_instance_;
}; };
} // namespace app } // namespace app

View File

@ -0,0 +1,24 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "d3d12_graphics_window.h"
namespace xe {
namespace ui {
namespace qt {
bool D3D12GraphicsWindow::Initialize() {
// TODO:
return true;
}
} // namespace qt
} // namespace ui
} // namespace xe

View File

@ -0,0 +1,31 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_QT_D3D12_GRAPHICS_WINDOW_H_
#define XENIA_UI_QT_D3D12_GRAPHICS_WINDOW_H_
#include "graphics_window.h"
namespace xe {
namespace ui {
namespace qt {
class D3D12GraphicsWindow : public GraphicsWindowImpl<> {
Q_OBJECT
D3D12GraphicsWindow(Emulator* emulator) : GraphicsWindowImpl(emulator) {}
public:
bool Initialize() override;
};
} // namespace qt
} // namespace ui
} // namespace xe
#endif

View File

@ -0,0 +1,45 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_QT_GRAPHICS_WINDOW_H_
#define XENIA_UI_QT_GRAPHICS_WINDOW_H_
#include <QWindow>
#include "xenia/emulator.h"
namespace xe {
namespace ui {
namespace qt {
class GraphicsWindow {
public:
GraphicsWindow(Emulator* emulator) : emulator_(emulator) {}
virtual ~GraphicsWindow() = default;
Emulator* emulator() const { return emulator_; }
virtual bool Initialize() = 0;
private:
Emulator* emulator_;
};
template <typename T = QWindow>
class GraphicsWindowImpl : public T, public GraphicsWindow {
static_assert(std::is_base_of_v<QWindow, T>,
"GraphicsWindow must inherit from a QWindow-based class");
public:
GraphicsWindowImpl(Emulator* emulator) : T(), GraphicsWindow(emulator) {}
};
} // namespace qt
} // namespace ui
} // namespace xe
#endif

View File

@ -0,0 +1,62 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "vulkan_graphics_window.h"
#include <QVulkanWindow>
#include "xenia/gpu/command_processor.h"
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
#include "xenia/ui/vulkan/vulkan_instance.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
namespace xe {
namespace ui {
namespace qt {
class VulkanRenderer : public QVulkanWindowRenderer {
public:
VulkanRenderer(VulkanGraphicsWindow* window,
gpu::vulkan::VulkanGraphicsSystem* graphics_system)
: window_(window), graphics_system_(graphics_system) {}
void startNextFrame() override {
// NEED TO DO STUFF HERE IDK
}
private:
VulkanGraphicsWindow* window_;
gpu::vulkan::VulkanGraphicsSystem* graphics_system_;
};
QVulkanWindowRenderer* VulkanGraphicsWindow::createRenderer() {
auto graphics_system = reinterpret_cast<gpu::vulkan::VulkanGraphicsSystem*>(
emulator()->graphics_system());
return new VulkanRenderer(
this, graphics_system);
}
bool VulkanGraphicsWindow::Initialize() {
// copied from DrChat's original Qt branch
auto provider = reinterpret_cast<ui::vulkan::VulkanProvider*>(
emulator()->graphics_system()->provider());
// Create a Qt wrapper around our vulkan instance.
vulkan_instance_.setVkInstance(*provider->instance());
if (!vulkan_instance_.create()) {
return false;
}
setVulkanInstance(&vulkan_instance_);
return true;
}
} // namespace qt
} // namespace ui
} // namespace xe

View File

@ -0,0 +1,38 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_QT_VULKAN_GRAPHICS_WINDOW_H_
#define XENIA_UI_QT_VULKAN_GRAPHICS_WINDOW_H_
#include <QVulkanWindow>
#include "graphics_window.h"
namespace xe {
namespace ui {
namespace qt {
class VulkanGraphicsWindow : public GraphicsWindowImpl<QVulkanWindow> {
Q_OBJECT
public:
VulkanGraphicsWindow(Emulator* emulator)
: GraphicsWindowImpl(emulator) {}
bool Initialize() override;
private:
QVulkanWindowRenderer* createRenderer() override;
QVulkanInstance vulkan_instance_;
};
} // namespace qt
} // namespace ui
} // namespace xe
#endif