Another change of heart: I'll just use Qt

This commit is contained in:
SimoneN64
2024-09-22 14:52:20 +02:00
parent 1a69c58458
commit 0aa0c0b654
232 changed files with 60 additions and 118039 deletions

View File

@@ -6,9 +6,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
add_compile_definitions(IMGUI_IMPL_VULKAN_USE_VOLK)
add_compile_definitions(IMGUI_IMPL_VULKAN_NO_PROTOTYPES)
if (WIN32)
add_compile_definitions(NOMINMAX)
endif ()
@@ -56,7 +53,6 @@ add_subdirectory(../backend backend)
add_subdirectory(../../external/parallel-rdp parallel-rdp)
add_subdirectory(../../external/unarr unarr)
add_subdirectory(../../external/SDL SDL)
add_subdirectory(../../external/imgui imgui)
set(CMAKE_AUTOMOC ON)
@@ -82,8 +78,8 @@ add_executable(kaizen-qt
AudioSettings.cpp
InputSettings.hpp
InputSettings.cpp
ImGuiWidget.hpp
ImGuiWidget.cpp)
Debugger.hpp
Debugger.cpp)
include(CheckCCompilerFlag)
@@ -100,7 +96,7 @@ if (${CMAKE_BUILD_TYPE} MATCHES Debug)
#target_link_options(kaizen-qt PUBLIC -fsanitize=address -fsanitize=undefined)
endif ()
target_link_libraries(kaizen-qt PUBLIC SDL3::SDL3 SDL3::SDL3-static Qt6::Core Qt6::Gui Qt6::Widgets discord-rpc fmt mio nlohmann_json parallel-rdp imgui backend)
target_link_libraries(kaizen-qt PUBLIC SDL3::SDL3 SDL3::SDL3-static Qt6::Core Qt6::Gui Qt6::Widgets discord-rpc fmt mio nlohmann_json parallel-rdp backend)
target_compile_definitions(kaizen-qt PUBLIC SDL_MAIN_HANDLED)
file(COPY ../../resources/ DESTINATION ${PROJECT_BINARY_DIR}/resources/)

15
src/frontend/Debugger.cpp Normal file
View File

@@ -0,0 +1,15 @@
#include <Debugger.hpp>
Debugger::Debugger() : QWidget(nullptr) {
disassembly = new QDockWidget(this);
disassembly->setWindowTitle("Disassembly");
disassembly->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
codeView = new QTreeView(disassembly);
codeView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
codeView->setHeaderHidden(true);
cpuState = new QDockWidget(this);
cpuState->setWindowTitle("Registers");
cpuState->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
registers = new QTreeView(cpuState);
registers->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}

12
src/frontend/Debugger.hpp Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <QDockWidget>
#include <QWidget>
#include <QTreeView>
class Debugger : public QWidget {
QDockWidget *disassembly{}, *cpuState{};
QTreeView *codeView{}, *registers{};
public:
Debugger();
};

View File

@@ -1,444 +0,0 @@
#include <ImGuiWidget.hpp>
#include <log.hpp>
#include <QWindow>
#include <qevent.h>
#include <SDL3/SDL_vulkan.h>
static void check_vk_result(VkResult err) {
if (err == 0)
return;
fprintf(stderr, "[vulkan] Error: VkResult = %d\n", err);
if (err < 0)
abort();
}
#ifdef APP_USE_VULKAN_DEBUG_REPORT
static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType,
uint64_t object, size_t location, int32_t messageCode,
const char *pLayerPrefix, const char *pMessage, void *pUserData) {
(void)flags;
(void)object;
(void)location;
(void)messageCode;
(void)pUserData;
(void)pLayerPrefix; // Unused arguments
fprintf(stderr, "[vulkan] Debug report from ObjectType: %i\nMessage: %s\n\n", objectType, pMessage);
return VK_FALSE;
}
#endif // APP_USE_VULKAN_DEBUG_REPORT
static bool IsExtensionAvailable(const std::vector<VkExtensionProperties> &properties, const char *extension) {
for (const VkExtensionProperties &p : properties)
if (strcmp(p.extensionName, extension) == 0)
return true;
return false;
}
void ImGuiWidget::SelectGpu() {
uint32_t gpu_count;
VkResult err = vkEnumeratePhysicalDevices(instance, &gpu_count, nullptr);
check_vk_result(err);
IM_ASSERT(gpu_count > 0);
std::vector<VkPhysicalDevice> gpus;
gpus.resize(gpu_count);
err = vkEnumeratePhysicalDevices(instance, &gpu_count, gpus.data());
check_vk_result(err);
// If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers
// most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple
// dedicated GPUs) is out of scope of this sample.
for (VkPhysicalDevice &device : gpus) {
VkPhysicalDeviceProperties properties;
vkGetPhysicalDeviceProperties(device, &properties);
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
gpu = device;
return;
}
}
// Use first GPU (Integrated) if a Discrete one is not available.
if (gpu_count > 0) {
gpu = gpus[0];
return;
}
Util::panic("[ImGui Widget] Could not find a suitable Vulkan GPU!");
}
void ImGuiWidget::InitVulkan(char const *const *instanceExtensions, uint32_t instanceExtensionsCount) {
VkResult err;
#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
volkInitialize();
#endif
// Create Vulkan Instance
{
VkInstanceCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
// Enumerate available extensions
uint32_t properties_count;
std::vector<VkExtensionProperties> properties;
vkEnumerateInstanceExtensionProperties(nullptr, &properties_count, nullptr);
properties.resize(properties_count);
err = vkEnumerateInstanceExtensionProperties(nullptr, &properties_count, properties.data());
check_vk_result(err);
std::vector<const char *> extensions;
extensions.resize(instanceExtensionsCount);
memcpy(extensions.data(), instanceExtensions, instanceExtensionsCount * sizeof(const char *));
// Enable required extensions
if (IsExtensionAvailable(properties, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
#ifdef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME
if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) {
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
create_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
}
#endif
// Enabling validation layers
#ifdef APP_USE_VULKAN_DEBUG_REPORT
const char *layers[] = {"VK_LAYER_KHRONOS_validation"};
create_info.enabledLayerCount = 1;
create_info.ppEnabledLayerNames = layers;
instance_extensions.push_back("VK_EXT_debug_report");
#endif
// Create Vulkan Instance
create_info.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
create_info.ppEnabledExtensionNames = extensions.data();
err = vkCreateInstance(&create_info, nullptr, &instance);
check_vk_result(err);
#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
volkLoadInstance(instance);
#endif
// Setup the debug report callback
#ifdef APP_USE_VULKAN_DEBUG_REPORT
auto f_vkCreateDebugReportCallbackEXT =
(PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT");
IM_ASSERT(f_vkCreateDebugReportCallbackEXT != nullptr);
VkDebugReportCallbackCreateInfoEXT debug_report_ci = {};
debug_report_ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
debug_report_ci.flags =
VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
debug_report_ci.pfnCallback = debug_report;
debug_report_ci.pUserData = nullptr;
err = f_vkCreateDebugReportCallbackEXT(instance, &debug_report_ci, nullptr, &g_DebugReport);
check_vk_result(err);
#endif
}
// Select Physical Device (GPU)
SelectGpu();
// Select graphics queue family
{
uint32_t count;
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
VkQueueFamilyProperties *queues = (VkQueueFamilyProperties *)malloc(sizeof(VkQueueFamilyProperties) * count);
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count, queues);
for (uint32_t i = 0; i < count; i++)
if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
queueFamily = i;
break;
}
free(queues);
IM_ASSERT(queueFamily != (uint32_t)-1);
}
// Create Logical Device (with 1 queue)
{
std::vector<const char *> device_extensions;
device_extensions.push_back("VK_KHR_swapchain");
// Enumerate physical device extension
uint32_t properties_count;
std::vector<VkExtensionProperties> properties;
vkEnumerateDeviceExtensionProperties(gpu, nullptr, &properties_count, nullptr);
properties.resize(properties_count);
vkEnumerateDeviceExtensionProperties(gpu, nullptr, &properties_count, properties.data());
#ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME))
device_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
#endif
const float queue_priority[] = {1.0f};
VkDeviceQueueCreateInfo queue_info[1] = {};
queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_info[0].queueFamilyIndex = queueFamily;
queue_info[0].queueCount = 1;
queue_info[0].pQueuePriorities = queue_priority;
VkDeviceCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
create_info.queueCreateInfoCount = sizeof(queue_info) / sizeof(queue_info[0]);
create_info.pQueueCreateInfos = queue_info;
create_info.enabledExtensionCount = (uint32_t)device_extensions.size();
create_info.ppEnabledExtensionNames = device_extensions.data();
err = vkCreateDevice(gpu, &create_info, nullptr, &device);
check_vk_result(err);
vkGetDeviceQueue(device, queueFamily, 0, &queue);
}
// Create Descriptor Pool
// The example only requires a single combined image sampler descriptor for the font image and only uses one
// descriptor set (for that) If you wish to load e.g. additional textures you may need to alter pools sizes.
{
VkDescriptorPoolSize pool_sizes[] = {
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1},
};
VkDescriptorPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
pool_info.maxSets = 1;
pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes);
pool_info.pPoolSizes = pool_sizes;
err = vkCreateDescriptorPool(device, &pool_info, nullptr, &descriptorPool);
check_vk_result(err);
}
}
void ImGuiWidget::InitWindow() {
mainWindowData.Surface = surface;
// Check for WSI support
VkBool32 res;
vkGetPhysicalDeviceSurfaceSupportKHR(gpu, queueFamily, mainWindowData.Surface, &res);
if (res != VK_TRUE) {
fprintf(stderr, "Error no WSI support on physical device 0\n");
exit(-1);
}
// Select Surface Format
const VkFormat requestSurfaceImageFormat[] = {VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM,
VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM};
const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
mainWindowData.SurfaceFormat =
ImGui_ImplVulkanH_SelectSurfaceFormat(gpu, mainWindowData.Surface, requestSurfaceImageFormat,
(size_t)IM_ARRAYSIZE(requestSurfaceImageFormat), requestSurfaceColorSpace);
// Select Present Mode
#ifdef APP_UNLIMITED_FRAME_RATE
VkPresentModeKHR present_modes[] = {VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR,
VK_PRESENT_MODE_FIFO_KHR};
#else
VkPresentModeKHR present_modes[] = {VK_PRESENT_MODE_FIFO_KHR};
#endif
mainWindowData.PresentMode =
ImGui_ImplVulkanH_SelectPresentMode(gpu, mainWindowData.Surface, &present_modes[0], IM_ARRAYSIZE(present_modes));
// printf("[vulkan] Selected PresentMode = %d\n", mainWindowData.PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
IM_ASSERT(minImageCount >= 2);
ImGui_ImplVulkanH_CreateOrResizeWindow(instance, gpu, device, &mainWindowData, queueFamily, nullptr, width(),
height(), minImageCount);
}
ImGuiWidget::ImGuiWidget(QWidget *parent) : QWidget(parent) {
setAttribute(Qt::WA_OpaquePaintEvent);
setAttribute(Qt::WA_NoSystemBackground);
setFocusPolicy(Qt::StrongFocus);
// HOWEVER, this important attribute stops the "paintEvent" slot from being called,
// thus we'll need to write our own method that paints to the screen every frame.
setAttribute(Qt::WA_PaintOnScreen);
windowHandle()->setSurfaceType(QWindow::VulkanSurface);
SDL_InitSubSystem(SDL_INIT_VIDEO);
#ifdef SDL_HINT_IME_SHOW_UI
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
#endif
auto winPtr = reinterpret_cast<void *>(winId());
auto props = SDL_CreateProperties();
#ifdef SDL_PLATFORM_LINUX
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_CREATE_WAYLAND_WL_SURFACE_POINTER, winPtr);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, reinterpret_cast<s64>(winPtr));
#elif SDL_PLATFORM_WINDOWS
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_CREATE_WIN32_HWND_POINTER, winPtr);
#else
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER, winPtr);
#endif
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_VULKAN_BOOLEAN, true);
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, true);
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, true);
window = SDL_CreateWindowWithProperties(props);
uint32_t extensionCount = 0;
auto extensions = SDL_Vulkan_GetInstanceExtensions(&extensionCount);
InitVulkan(extensions, extensionCount);
if (!SDL_Vulkan_CreateSurface(window, instance, nullptr, &surface)) {
Util::panic("[ImGui Widget]: Failed to create Vulkan surface.\n");
}
InitWindow();
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO &io = ImGui::GetIO();
(void)io;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
// io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
// io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
// Setup Dear ImGui style
ImGui::StyleColorsDark();
// ImGui::StyleColorsLight();
// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
ImGuiStyle &style = ImGui::GetStyle();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
style.WindowRounding = 0.0f;
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
}
// Setup Platform/Renderer backends
ImGui_ImplSDL3_InitForVulkan(window);
ImGui_ImplVulkan_InitInfo init_info = {};
init_info.Instance = instance;
init_info.PhysicalDevice = gpu;
init_info.Device = device;
init_info.QueueFamily = queueFamily;
init_info.Queue = queue;
init_info.PipelineCache = pipelineCache;
init_info.DescriptorPool = descriptorPool;
init_info.RenderPass = mainWindowData.RenderPass;
init_info.Subpass = 0;
init_info.MinImageCount = minImageCount;
init_info.ImageCount = mainWindowData.ImageCount;
init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
init_info.Allocator = nullptr;
init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info);
}
void ImGuiWidget::resizeEvent(QResizeEvent *event) {
if (event->size().width() > 0 && event->size().height() > 0 &&
(swapChainRebuild || mainWindowData.Width != event->size().width() ||
mainWindowData.Height != event->size().height())) {
ImGui_ImplVulkan_SetMinImageCount(minImageCount);
ImGui_ImplVulkanH_CreateOrResizeWindow(instance, gpu, device, &mainWindowData, queueFamily, nullptr,
event->size().width(), event->size().height(), minImageCount);
mainWindowData.FrameIndex = 0;
swapChainRebuild = false;
}
}
void ImGuiWidget::showEvent(QShowEvent *) {
connect(&timer, &QTimer::timeout, this, &ImGuiWidget::Repaint);
timer.setInterval(16);
timer.start();
}
void ImGuiWidget::Repaint() {
ImGui_ImplVulkan_NewFrame();
ImGui_ImplSDL3_NewFrame();
ImGui::NewFrame();
ImGui::ShowDemoWindow();
ImGui::Render();
FrameRender(ImGui::GetDrawData());
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
FramePresent();
}
void ImGuiWidget::FrameRender(ImDrawData *drawData) {
VkResult err;
VkSemaphore image_acquired_semaphore =
mainWindowData.FrameSemaphores[mainWindowData.SemaphoreIndex].ImageAcquiredSemaphore;
VkSemaphore render_complete_semaphore =
mainWindowData.FrameSemaphores[mainWindowData.SemaphoreIndex].RenderCompleteSemaphore;
err = vkAcquireNextImageKHR(device, mainWindowData.Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE,
&mainWindowData.FrameIndex);
if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) {
swapChainRebuild = true;
return;
}
check_vk_result(err);
ImGui_ImplVulkanH_Frame *fd = &mainWindowData.Frames[mainWindowData.FrameIndex];
{
err = vkWaitForFences(device, 1, &fd->Fence, VK_TRUE,
UINT64_MAX); // wait indefinitely instead of periodically checking
check_vk_result(err);
err = vkResetFences(device, 1, &fd->Fence);
check_vk_result(err);
}
{
err = vkResetCommandPool(device, fd->CommandPool, 0);
check_vk_result(err);
VkCommandBufferBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
err = vkBeginCommandBuffer(fd->CommandBuffer, &info);
check_vk_result(err);
}
{
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = mainWindowData.RenderPass;
info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = mainWindowData.Width;
info.renderArea.extent.height = mainWindowData.Height;
info.clearValueCount = 1;
info.pClearValues = &mainWindowData.ClearValue;
vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
}
// Record dear imgui primitives into command buffer
ImGui_ImplVulkan_RenderDrawData(drawData, fd->CommandBuffer);
// Submit command buffer
vkCmdEndRenderPass(fd->CommandBuffer);
{
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
info.waitSemaphoreCount = 1;
info.pWaitSemaphores = &image_acquired_semaphore;
info.pWaitDstStageMask = &wait_stage;
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
err = vkQueueSubmit(queue, 1, &info, fd->Fence);
check_vk_result(err);
}
}
void ImGuiWidget::FramePresent() {
if (swapChainRebuild)
return;
VkSemaphore render_complete_semaphore =
mainWindowData.FrameSemaphores[mainWindowData.SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
info.pWaitSemaphores = &render_complete_semaphore;
info.swapchainCount = 1;
info.pSwapchains = &mainWindowData.Swapchain;
info.pImageIndices = &mainWindowData.FrameIndex;
VkResult err = vkQueuePresentKHR(queue, &info);
if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) {
swapChainRebuild = true;
return;
}
check_vk_result(err);
mainWindowData.SemaphoreIndex =
(mainWindowData.SemaphoreIndex + 1) % mainWindowData.SemaphoreCount; // Now we can use the next set of semaphores
}

View File

@@ -1,43 +0,0 @@
#pragma once
#include <imgui.h>
#include <imgui_impl_sdl3.h>
#include <imgui_impl_vulkan.h>
#include <SDL3/SDL.h>
#include <QTimer>
#include <QWidget>
class ImGuiWidget : public QWidget {
QTimer timer;
SDL_Window *window{};
VkInstance instance = VK_NULL_HANDLE;
VkPhysicalDevice gpu = VK_NULL_HANDLE;
VkDevice device = VK_NULL_HANDLE;
uint32_t queueFamily = static_cast<uint32_t>(-1);
VkQueue queue = VK_NULL_HANDLE;
VkDebugReportCallbackEXT debugReport = VK_NULL_HANDLE;
VkPipelineCache pipelineCache = VK_NULL_HANDLE;
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
VkSurfaceKHR surface;
ImGui_ImplVulkanH_Window mainWindowData;
uint32_t minImageCount = 2;
bool swapChainRebuild = false;
void SelectGpu();
void InitVulkan(char const *const *, uint32_t);
void InitWindow();
void FrameRender(ImDrawData *);
void FramePresent();
public slots:
void Repaint();
public:
[[nodiscard]] QPaintEngine *paintEngine() const override { return nullptr; }
ImGuiWidget(QWidget* parent);
void resizeEvent(QResizeEvent *event) override;
void showEvent(QShowEvent *) override;
};

View File

@@ -11,6 +11,7 @@ KaizenQt::KaizenQt() noexcept : QWidget(nullptr) {
mainWindow = std::make_unique<MainWindow>();
settingsWindow = std::make_unique<SettingsWindow>();
emuThread = std::make_unique<EmuThread>(*mainWindow->vulkanWidget, *settingsWindow);
debugger = std::make_unique<Debugger>();
ConnectMainWindowSignalsToSlots();
Util::RPC::GetInstance().Update(Util::RPC::Idling);
@@ -20,17 +21,19 @@ KaizenQt::KaizenQt() noexcept : QWidget(nullptr) {
setFocus();
grabKeyboard();
mainWindow->show();
debugger->hide();
settingsWindow->hide();
connect(settingsWindow.get(), &SettingsWindow::regrabKeyboard, this, [&]() { grabKeyboard(); });
connect(settingsWindow.get(), &SettingsWindow::regrabKeyboard, this, [&] { grabKeyboard(); });
}
void KaizenQt::ConnectMainWindowSignalsToSlots() noexcept {
connect(mainWindow.get(), &MainWindow::OpenSettings, this, [this]() { settingsWindow->show(); });
connect(mainWindow.get(), &MainWindow::OpenSettings, this, [this] { settingsWindow->show(); });
connect(mainWindow.get(), &MainWindow::OpenDebugger, this, [this] { debugger->show(); });
connect(mainWindow.get(), &MainWindow::OpenROM, this, &KaizenQt::LoadROM);
connect(mainWindow.get(), &MainWindow::Exit, this, &KaizenQt::Quit);
connect(mainWindow.get(), &MainWindow::Reset, emuThread.get(), &EmuThread::Reset);
connect(mainWindow.get(), &MainWindow::Stop, emuThread.get(), &EmuThread::Stop);
connect(mainWindow.get(), &MainWindow::Stop, this, [this]() { mainWindow->setWindowTitle("Kaizen"); });
connect(mainWindow.get(), &MainWindow::Stop, this, [this] { mainWindow->setWindowTitle("Kaizen"); });
connect(mainWindow.get(), &MainWindow::Pause, emuThread.get(), &EmuThread::TogglePause);
}

View File

@@ -38,4 +38,5 @@ private:
std::unique_ptr<MainWindow> mainWindow;
std::unique_ptr<SettingsWindow> settingsWindow;
std::unique_ptr<EmuThread> emuThread;
std::unique_ptr<Debugger> debugger;
};

View File

@@ -11,6 +11,8 @@ MainWindow::MainWindow() noexcept {
if (objectName().isEmpty())
setObjectName("MainWindow");
resize(800, 646);
actionOpenDebuggerWindow = new QAction(this);
actionOpenDebuggerWindow->setObjectName("actionOpenDebuggerWindow");
actionAbout = new QAction(this);
actionAbout->setObjectName("actionAbout");
actionOpen = new QAction(this);
@@ -27,22 +29,16 @@ MainWindow::MainWindow() noexcept {
actionSettings->setObjectName("actionSettings");
centralwidget = new QWidget(this);
centralwidget->setObjectName("centralwidget");
verticalLayout = new QVBoxLayout(centralwidget);
verticalLayout = new QVBoxLayout;
verticalLayout->setSpacing(0);
verticalLayout->setObjectName("verticalLayout");
verticalLayout->setContentsMargins(0, 0, 0, 0);
horizontalLayout = new QHBoxLayout(centralwidget);
horizontalLayout->setSpacing(0);
verticalLayout->setObjectName("horizontalLayout");
verticalLayout->setContentsMargins(0, 0, 0, 0);
vulkanWidget = new RenderWidget(centralwidget);
vulkanWidget = new RenderWidget;
vulkanWidget->setObjectName("vulkanWidget");
debugger = new ImGuiWidget(centralwidget);
debugger->setObjectName("debugger");
horizontalLayout->addWidget(vulkanWidget);
horizontalLayout->addWidget(debugger);
verticalLayout->addLayout(horizontalLayout);
verticalLayout->addWidget(vulkanWidget);
centralwidget->setLayout(verticalLayout);
setCentralWidget(centralwidget);
menubar = new QMenuBar(this);
@@ -52,6 +48,8 @@ MainWindow::MainWindow() noexcept {
menuFile->setObjectName("menuFile");
menuEmulation = new QMenu(menubar);
menuEmulation->setObjectName("menuEmulation");
menuTools = new QMenu(menubar);
menuTools->setObjectName("menuTools");
menuAbout = new QMenu(menubar);
menuAbout->setObjectName("menuAbout");
setMenuBar(menubar);
@@ -61,6 +59,7 @@ MainWindow::MainWindow() noexcept {
menubar->addAction(menuFile->menuAction());
menubar->addAction(menuEmulation->menuAction());
menubar->addAction(menuTools->menuAction());
menubar->addAction(menuAbout->menuAction());
menuFile->addAction(actionOpen);
menuFile->addAction(actionExit);
@@ -68,6 +67,7 @@ MainWindow::MainWindow() noexcept {
menuEmulation->addAction(actionPause);
menuEmulation->addAction(actionReset);
menuEmulation->addAction(actionStop);
menuTools->addAction(actionOpenDebuggerWindow);
menuAbout->addAction(actionAbout);
Retranslate();
@@ -82,42 +82,29 @@ MainWindow::MainWindow() noexcept {
void MainWindow::Retranslate() {
setWindowTitle(QCoreApplication::translate("MainWindow", "Kaizen", nullptr));
actionOpenDebuggerWindow->setText(QCoreApplication::translate("MainWindow", "CPU Debugger", nullptr));
actionOpenDebuggerWindow->setStatusTip(QCoreApplication::translate(
"MainWindow", "Open the CPU debugger window which allows you see registers, memory and disassembled code",
nullptr));
actionAbout->setText(QCoreApplication::translate("MainWindow", "About Kaizen", nullptr));
#if QT_CONFIG(statustip)
actionAbout->setStatusTip(QCoreApplication::translate("MainWindow", "About this emulator", nullptr));
#endif // QT_CONFIG(statustip)
actionOpen->setText(QCoreApplication::translate("MainWindow", "Open...", nullptr));
#if QT_CONFIG(statustip)
actionOpen->setStatusTip(QCoreApplication::translate("MainWindow", "Open a ROM", nullptr));
#endif // QT_CONFIG(statustip)
#if QT_CONFIG(shortcut)
actionOpen->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+O", nullptr));
#endif // QT_CONFIG(shortcut)
actionExit->setText(QCoreApplication::translate("MainWindow", "Exit", nullptr));
#if QT_CONFIG(statustip)
actionExit->setStatusTip(QCoreApplication::translate("MainWindow", "Quit the emulator", nullptr));
#endif // QT_CONFIG(statustip)
actionPause->setText(QCoreApplication::translate("MainWindow", "Pause", nullptr));
#if QT_CONFIG(statustip)
actionPause->setStatusTip(QCoreApplication::translate("MainWindow", "Pause the emulation", nullptr));
#endif // QT_CONFIG(statustip)
actionReset->setText(QCoreApplication::translate("MainWindow", "Reset", nullptr));
#if QT_CONFIG(statustip)
actionReset->setStatusTip(QCoreApplication::translate("MainWindow", "Reset the emulation", nullptr));
#endif // QT_CONFIG(statustip)
actionStop->setText(QCoreApplication::translate("MainWindow", "Stop", nullptr));
#if QT_CONFIG(statustip)
actionStop->setStatusTip(QCoreApplication::translate("MainWindow", "Stop the emulation", nullptr));
#endif // QT_CONFIG(statustip)
actionSettings->setText(QCoreApplication::translate("MainWindow", "Settings", nullptr));
#if QT_CONFIG(tooltip)
actionSettings->setToolTip(QCoreApplication::translate("MainWindow", "Settings", nullptr));
#endif // QT_CONFIG(tooltip)
#if QT_CONFIG(statustip)
actionSettings->setStatusTip(QCoreApplication::translate("MainWindow", "Open the settings window", nullptr));
#endif // QT_CONFIG(statustip)
menuFile->setTitle(QCoreApplication::translate("MainWindow", "File", nullptr));
menuEmulation->setTitle(QCoreApplication::translate("MainWindow", "Emulation", nullptr));
menuTools->setTitle(QCoreApplication::translate("MainWindow", "Tools", nullptr));
menuAbout->setTitle(QCoreApplication::translate("MainWindow", "Help", nullptr));
} // retranslateUi
@@ -162,4 +149,5 @@ void MainWindow::ConnectSignalsToSlots() noexcept {
});
connect(actionSettings, &QAction::triggered, this, [this]() { emit OpenSettings(); });
connect(actionOpenDebuggerWindow, &QAction::triggered, this, [this]() { emit OpenDebugger(); });
}

View File

@@ -3,7 +3,7 @@
#include <QMainWindow>
#include <QVBoxLayout>
#include <RenderWidget.hpp>
#include <ImGuiWidget.hpp>
#include <Debugger.hpp>
class MainWindow : public QMainWindow {
Q_OBJECT
@@ -11,6 +11,7 @@ class MainWindow : public QMainWindow {
public:
MainWindow() noexcept;
QAction *actionOpenDebuggerWindow;
QAction *actionAbout;
QAction *actionOpen;
QAction *actionExit;
@@ -20,12 +21,11 @@ public:
QAction *actionSettings;
QWidget *centralwidget;
QVBoxLayout *verticalLayout;
QHBoxLayout *horizontalLayout;
RenderWidget *vulkanWidget;
ImGuiWidget *debugger;
QMenuBar *menubar;
QMenu *menuFile;
QMenu *menuEmulation;
QMenu *menuTools;
QMenu *menuAbout;
QStatusBar *statusbar;
@@ -36,6 +36,7 @@ private:
bool textPauseToggle = false;
Q_SIGNALS:
void OpenDebugger();
void OpenSettings();
void OpenROM(const QString &rom_file);
void Exit();

View File

@@ -1,7 +1,7 @@
#include <KaizenQt.hpp>
#include <RenderWidget.hpp>
RenderWidget::RenderWidget(QWidget *parent) : QWidget(parent) {
RenderWidget::RenderWidget() : QWidget(nullptr) {
setAttribute(Qt::WA_NativeWindow);
setAttribute(Qt::WA_PaintOnScreen);
if (GetOSCompositorCategory() == CompositorCategory::Wayland) {

View File

@@ -79,7 +79,7 @@ public:
class RenderWidget : public QWidget {
public:
[[nodiscard]] VkInstance instance() const { return qtVkInstanceFactory->handle.vkInstance(); }
explicit RenderWidget(QWidget *parent);
explicit RenderWidget();
[[nodiscard]] QPaintEngine *paintEngine() const override { return nullptr; }