[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 "emulator_window.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/base/clock.h"
#include "xenia/base/cvar.h"
#include "xenia/base/debugging.h"
#include "xenia/base/factory.h"
#include "xenia/base/logging.h"
#include "xenia/base/platform.h"
#include "xenia/base/profiling.h"
#include "xenia/base/threading.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/null/null_graphics_system.h"
#include "xenia/gpu/vulkan/vulkan_graphics_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/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(gpu, "any", "Graphics system. Use: [any, vulkan, null]",
@ -41,158 +48,97 @@ DEFINE_bool(fullscreen, false, "Toggles fullscreen", "General");
namespace xe {
namespace app {
class VulkanWindow : public QVulkanWindow {
public:
VulkanWindow(gpu::vulkan::VulkanGraphicsSystem* gfx)
: graphics_system_(gfx) {}
QVulkanWindowRenderer* createRenderer() override;
std::unique_ptr<apu::AudioSystem> CreateAudioSystem(cpu::Processor* processor) {
Factory<apu::AudioSystem, cpu::Processor*> factory;
#if XE_PLATFORM_WIN32
factory.Add<apu::xaudio2::XAudio2AudioSystem>("xaudio2");
#endif // XE_PLATFORM_WIN32
factory.Add<apu::sdl::SDLAudioSystem>("sdl");
factory.Add<apu::nop::NopAudioSystem>("nop");
return factory.Create(cvars::apu, processor);
}
private:
gpu::vulkan::VulkanGraphicsSystem* graphics_system_;
};
std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() {
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 {
public:
VulkanRenderer(VulkanWindow* window,
gpu::vulkan::VulkanGraphicsSystem* graphics_system)
: window_(window), graphics_system_(graphics_system) {}
void startNextFrame() override {
// Copy the graphics frontbuffer to our backbuffer.
//auto swap_state = graphics_system_->swap_state();
auto cmd = window_->currentCommandBuffer();
//auto src = reinterpret_cast<VkImage>(
// swap_state->buffer_textures[swap_state->current_buffer]);
auto dest = window_->swapChainImage(window_->currentSwapChainImageIndex());
auto dest_size = window_->swapChainImageSize();
VkImageMemoryBarrier barrier;
std::memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
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();
std::vector<std::unique_ptr<hid::InputDriver>> CreateInputDrivers(
ui::Window* window) {
std::vector<std::unique_ptr<hid::InputDriver>> drivers;
if (cvars::hid.compare("nop") == 0) {
drivers.emplace_back(hid::nop::Create(window));
} else {
Factory<hid::InputDriver, ui::Window*> factory;
#if XE_PLATFORM_WIN32
factory.Add("xinput", hid::xinput::Create);
// WinKey input driver should always be the last input driver added!
factory.Add("winkey", hid::winkey::Create);
#endif // XE_PLATFORM_WIN32
factory.Add("sdl", hid::sdl::Create);
for (auto& driver : factory.CreateAll(cvars::hid, window)) {
if (XSUCCEEDED(driver->Setup())) {
drivers.emplace_back(std::move(driver));
}
private:
gpu::vulkan::VulkanGraphicsSystem* graphics_system_;
VulkanWindow* window_;
};
QVulkanWindowRenderer* VulkanWindow::createRenderer() {
return new VulkanRenderer(this, graphics_system_);
}
if (drivers.empty()) {
// Fallback to nop if none created.
drivers.emplace_back(xe::hid::nop::Create(window));
}
}
return drivers;
}
EmulatorWindow::EmulatorWindow(Loop* loop, const std::string& title)
: QtWindow(loop, title) {
// 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,
kernel::KernelState* kernel_state) {
auto audio = apu::xaudio2::XAudio2AudioSystem::Create(processor);
if (audio->Setup(kernel_state) != X_STATUS_SUCCESS) {
audio->Shutdown();
return std::unique_ptr<apu::AudioSystem>(nullptr);
X_STATUS result = emulator_->Setup(this, CreateAudioSystem,
CreateGraphicsSystem, CreateInputDrivers);
if (result == X_STATUS_SUCCESS) {
// Setup a callback called when the emulator wants to swap.
emulator_->graphics_system()->command_processor()->set_swap_request_handler(
[&]() {
auto graphics_window =
reinterpret_cast<QWindow*>(this->graphics_window_.get());
QMetaObject::invokeMethod(graphics_window, "requestUpdate",
Qt::QueuedConnection);
});
}
return audio;
};
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);
if (!EmulatorWindow::Initialize()) {
return;
}
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));
// }
// }
//});
// 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::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()) {
bool EmulatorWindow::Initialize() {
if (!graphics_window_->Initialize()) {
XELOGE("Could not initialize graphics window");
return false;
}
graphics_window_ = std::make_unique<VulkanWindow>(
reinterpret_cast<gpu::vulkan::VulkanGraphicsSystem*>(
emulator_->graphics_system()));
graphics_window_->setVulkanInstance(vulkan_instance_.get());
// 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);
return true;

View File

@ -2,7 +2,7 @@
******************************************************************************
* 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. *
******************************************************************************
*/
@ -10,15 +10,11 @@
#ifndef XENIA_APP_MAIN_WINDOW_H_
#define XENIA_APP_MAIN_WINDOW_H_
#include <QMainWindow>
#include <QVulkanInstance>
#include <QWindow>
#include "xenia/emulator.h"
#include "xenia/ui/graphics_context.h"
#include "xenia/ui/graphics_provider.h"
#include "xenia/ui/qt/window_qt.h"
#include "xenia/ui/qt/graphics_window.h"
#include "xenia/ui/qt/loop_qt.h"
#include "xenia/ui/qt/window_qt.h"
namespace xe {
namespace app {
@ -26,36 +22,28 @@ namespace app {
class VulkanWindow;
class VulkanRenderer;
using ui::qt::QtWindow;
using ui::Loop;
using ui::qt::GraphicsWindow;
using ui::qt::QtWindow;
class EmulatorWindow : public ui::qt::QtWindow {
class EmulatorWindow : public QtWindow {
Q_OBJECT
public:
EmulatorWindow(Loop *loop, const std::string& title);
EmulatorWindow(Loop* loop, const std::string& title);
bool Launch(const std::string& path);
xe::Emulator* emulator() { return emulator_.get(); }
protected:
// Events
private slots:
Emulator* emulator() const { return emulator_.get(); }
GraphicsWindow* graphics_window() const { return graphics_window_.get(); }
hid::InputSystem* input_system() const { return input_system_.get(); }
private:
bool Initialize() override;
void CreateMenuBar();
bool InitializeVulkan();
std::unique_ptr<xe::Emulator> emulator_;
std::unique_ptr<QWindow> graphics_window_;
std::unique_ptr<ui::GraphicsProvider> graphics_provider_;
std::unique_ptr<Emulator> emulator_;
std::unique_ptr<GraphicsWindow> graphics_window_;
std::unique_ptr<hid::InputSystem> input_system_;
std::unique_ptr<QVulkanInstance> vulkan_instance_;
};
} // 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