Clean up graphics context code

This commit is contained in:
wheremyfoodat 2025-07-26 03:42:59 +03:00
commit 807c15a824
12 changed files with 41 additions and 57 deletions

View file

@ -110,7 +110,6 @@ class GPU {
void deinitGraphicsContext() { renderer->deinitGraphicsContext(); } void deinitGraphicsContext() { renderer->deinitGraphicsContext(); }
void initGraphicsContext(void* window) { renderer->initGraphicsContext(window); } void initGraphicsContext(void* window) { renderer->initGraphicsContext(window); }
void initGraphicsContext(GL::Context* context) { renderer->initGraphicsContext(context); }
void fireDMA(u32 dest, u32 source, u32 size); void fireDMA(u32 dest, u32 source, u32 size);
void reset(); void reset();

View file

@ -106,11 +106,8 @@ class Emulator {
bool loadELF(const std::filesystem::path& path); bool loadELF(const std::filesystem::path& path);
bool loadELF(std::ifstream& file); bool loadELF(std::ifstream& file);
#ifdef PANDA3DS_FRONTEND_QT // For passing the SDL Window, GL context, etc from the frontend to the renderer
// For passing the GL context from Qt to the renderer void initGraphicsContext(void* context) { gpu.initGraphicsContext(context); }
void initGraphicsContext(GL::Context* glContext) { gpu.initGraphicsContext(glContext); }
void initGraphicsContext(void* window) { gpu.initGraphicsContext(window); }
#endif
RomFS::DumpingResult dumpRomFS(const std::filesystem::path& path); RomFS::DumpingResult dumpRomFS(const std::filesystem::path& path);
void setOutputSize(u32 width, u32 height) { gpu.setOutputSize(width, height); } void setOutputSize(u32 width, u32 height) { gpu.setOutputSize(width, height); }

View file

@ -136,7 +136,7 @@ class MainWindow : public QMainWindow {
void loadKeybindings(); void loadKeybindings();
void saveKeybindings(); void saveKeybindings();
// Tracks whether we are using an OpenGL-backed renderer or a Vulkan-backed renderer // Tracks what graphics API is backing our renderer
bool usingGL = false; bool usingGL = false;
bool usingVk = false; bool usingVk = false;
bool usingMtl = false; bool usingMtl = false;

View file

@ -9,14 +9,14 @@
// OpenGL widget for drawing the 3DS screen // OpenGL widget for drawing the 3DS screen
class ScreenWidget : public QWidget { class ScreenWidget : public QWidget {
enum class API { OpenGL, Metal, Vulkan };
Q_OBJECT Q_OBJECT
public: public:
using ResizeCallback = std::function<void(u32, u32)>; using ResizeCallback = std::function<void(u32, u32)>;
ScreenWidget(ResizeCallback resizeCallback, QWidget* parent = nullptr); enum class API { OpenGL, Metal, Vulkan };
ScreenWidget(API api, ResizeCallback resizeCallback, QWidget* parent = nullptr);
void resizeEvent(QResizeEvent* event) override; void resizeEvent(QResizeEvent* event) override;
// Called by the emulator thread for resizing the actual GL surface, since the emulator thread owns the GL context // Called by the emulator thread for resizing the actual GL surface, since the emulator thread owns the GL context
void resizeSurface(u32 width, u32 height); void resizeSurface(u32 width, u32 height);

View file

@ -101,11 +101,6 @@ class Renderer {
// Returns whether this draw is eligible for using hardware-accelerated shaders or if shaders should run on the CPU // Returns whether this draw is eligible for using hardware-accelerated shaders or if shaders should run on the CPU
virtual bool prepareForDraw(ShaderUnit& shaderUnit, PICA::DrawAcceleration* accel) { return false; } virtual bool prepareForDraw(ShaderUnit& shaderUnit, PICA::DrawAcceleration* accel) { return false; }
// Functions for initializing the graphics context for the Qt frontend, where we don't have the convenience of SDL_Window
#ifdef PANDA3DS_FRONTEND_QT
virtual void initGraphicsContext(GL::Context* context) { Helpers::panic("Tried to initialize incompatible renderer with GL context"); }
#endif
void setFBSize(u32 width, u32 height) { void setFBSize(u32 width, u32 height) {
fbSize[0] = width; fbSize[0] = width;
fbSize[1] = height; fbSize[1] = height;

View file

@ -211,10 +211,6 @@ class RendererGL final : public Renderer {
void resetStateManager() { gl.reset(); } void resetStateManager() { gl.reset(); }
void initUbershader(OpenGL::Program& program); void initUbershader(OpenGL::Program& program);
#ifdef PANDA3DS_FRONTEND_QT
virtual void initGraphicsContext([[maybe_unused]] GL::Context* context) override { initGraphicsContextInternal(); }
#endif
// Take a screenshot of the screen and store it in a file // Take a screenshot of the screen and store it in a file
void screenshot(const std::string& name) override; void screenshot(const std::string& name) override;
}; };

View file

@ -37,10 +37,6 @@ class RendererMTL final : public Renderer {
void screenshot(const std::string& name) override; void screenshot(const std::string& name) override;
void deinitGraphicsContext() override; void deinitGraphicsContext() override;
#ifdef PANDA3DS_FRONTEND_QT
virtual void initGraphicsContext([[maybe_unused]] GL::Context* context) override {}
#endif
virtual void setMTKLayer(void* layer) override; virtual void setMTKLayer(void* layer) override;
private: private:

View file

@ -20,8 +20,4 @@ class RendererNull final : public Renderer {
// Tell the GPU core that we'll handle vertex fetch & shader execution in the renderer in order to speed up execution. // Tell the GPU core that we'll handle vertex fetch & shader execution in the renderer in order to speed up execution.
// Of course, we don't do this and geometry is never actually processed, since this is the null renderer. // Of course, we don't do this and geometry is never actually processed, since this is the null renderer.
virtual bool prepareForDraw(ShaderUnit& shaderUnit, PICA::DrawAcceleration* accel) override { return true; }; virtual bool prepareForDraw(ShaderUnit& shaderUnit, PICA::DrawAcceleration* accel) override { return true; };
#ifdef PANDA3DS_FRONTEND_QT
virtual void initGraphicsContext([[maybe_unused]] GL::Context* context) override {}
#endif
}; };

View file

@ -16,8 +16,4 @@ class RendererSw final : public Renderer {
void drawVertices(PICA::PrimType primType, std::span<const PICA::Vertex> vertices) override; void drawVertices(PICA::PrimType primType, std::span<const PICA::Vertex> vertices) override;
void screenshot(const std::string& name) override; void screenshot(const std::string& name) override;
void deinitGraphicsContext() override; void deinitGraphicsContext() override;
#ifdef PANDA3DS_FRONTEND_QT
virtual void initGraphicsContext([[maybe_unused]] GL::Context* context) override {}
#endif
}; };

View file

@ -57,8 +57,6 @@ void RendererMTL::reset() {
colorRenderTargetCache.reset(); colorRenderTargetCache.reset();
} }
void RendererMTL::setMTKLayer(void* layer) {
metalLayer = (CA::MetalLayer*)layer;
void RendererMTL::setMTKLayer(void* layer) { metalLayer = (CA::MetalLayer*)layer; } void RendererMTL::setMTKLayer(void* layer) { metalLayer = (CA::MetalLayer*)layer; }
void RendererMTL::display() { void RendererMTL::display() {

View file

@ -25,8 +25,19 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
resize(800, 240 * 4); resize(800, 240 * 4);
show(); show();
const RendererType rendererType = emu->getConfig().rendererType;
usingGL = (rendererType == RendererType::OpenGL || rendererType == RendererType::Software || rendererType == RendererType::Null);
usingVk = (rendererType == RendererType::Vulkan);
usingMtl = (rendererType == RendererType::Metal);
ScreenWidget::API api = ScreenWidget::API::OpenGL;
if (usingVk)
api = ScreenWidget::API::Vulkan;
else if (usingMtl)
api = ScreenWidget::API::Metal;
// We pass a callback to the screen widget that will be triggered every time we resize the screen // We pass a callback to the screen widget that will be triggered every time we resize the screen
screen = new ScreenWidget([this](u32 width, u32 height) { handleScreenResize(width, height); }, this); screen = new ScreenWidget(api, [this](u32 width, u32 height) { handleScreenResize(width, height); }, this);
setCentralWidget(screen); setCentralWidget(screen);
appRunning = true; appRunning = true;
@ -149,29 +160,29 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
// The emulator graphics context for the thread should be initialized in the emulator thread due to how GL contexts work // The emulator graphics context for the thread should be initialized in the emulator thread due to how GL contexts work
emuThread = std::thread([this]() { emuThread = std::thread([this]() {
const RendererType rendererType = emu->getConfig().rendererType; switch (screen->api) {
usingGL = (rendererType == RendererType::OpenGL || rendererType == RendererType::Software || rendererType == RendererType::Null); case ScreenWidget::API::OpenGL: {
usingVk = (rendererType == RendererType::Vulkan); // Make GL context current for this thread, enable VSync
usingMtl = (rendererType == RendererType::Metal); GL::Context* glContext = screen->getGLContext();
glContext->MakeCurrent();
glContext->SetSwapInterval(emu->getConfig().vsyncEnabled ? 1 : 0);
if (usingGL) { if (glContext->IsGLES()) {
// Make GL context current for this thread, enable VSync emu->getRenderer()->setupGLES();
GL::Context* glContext = screen->getGLContext(); }
glContext->MakeCurrent();
glContext->SetSwapInterval(emu->getConfig().vsyncEnabled ? 1 : 0);
if (glContext->IsGLES()) { emu->initGraphicsContext(glContext);
emu->getRenderer()->setupGLES(); break;
} }
emu->initGraphicsContext(glContext); case ScreenWidget::API::Metal: {
} else if (usingVk) { emu->initGraphicsContext(nullptr);
Helpers::panic("Vulkan on Qt is currently WIP, try the SDL frontend instead!"); emu->getRenderer()->setMTKLayer(screen->getMTKLayer());
} else if (usingMtl) { break;
emu->initGraphicsContext((void*)nullptr); }
emu->getRenderer()->setMTKLayer(screen->getMTKLayer());
} else { case ScreenWidget::API::Vulkan: Helpers::panic("Vulkan on Qt is currently WIP, try the SDL frontend instead!"); break;
Helpers::panic("Unsupported graphics backend for Qt frontend!"); default: Helpers::panic("Unsupported graphics backend for Qt frontend!"); break;
} }
// We have to initialize controllers on the same thread they'll be polled in // We have to initialize controllers on the same thread they'll be polled in

View file

@ -18,10 +18,8 @@
// and https://github.com/melonDS-emu/melonDS/blob/master/src/frontend/qt_sdl/main.cpp // and https://github.com/melonDS-emu/melonDS/blob/master/src/frontend/qt_sdl/main.cpp
#ifdef PANDA3DS_ENABLE_OPENGL #ifdef PANDA3DS_ENABLE_OPENGL
ScreenWidget::ScreenWidget(ResizeCallback resizeCallback, QWidget* parent) : QWidget(parent), resizeCallback(resizeCallback) { ScreenWidget::ScreenWidget(API api, ResizeCallback resizeCallback, QWidget* parent) : api(api), QWidget(parent), resizeCallback(resizeCallback) {
// Create a native window for use with our graphics API of choice // Create a native window for use with our graphics API of choice
resize(800, 240 * 4);
setAutoFillBackground(false); setAutoFillBackground(false);
setAttribute(Qt::WA_NativeWindow, true); setAttribute(Qt::WA_NativeWindow, true);
setAttribute(Qt::WA_NoSystemBackground, true); setAttribute(Qt::WA_NoSystemBackground, true);
@ -29,7 +27,6 @@ ScreenWidget::ScreenWidget(ResizeCallback resizeCallback, QWidget* parent) : QWi
setAttribute(Qt::WA_KeyCompression, false); setAttribute(Qt::WA_KeyCompression, false);
setFocusPolicy(Qt::StrongFocus); setFocusPolicy(Qt::StrongFocus);
setMouseTracking(true); setMouseTracking(true);
show();
if (api == API::OpenGL) { if (api == API::OpenGL) {
if (!createGLContext()) { if (!createGLContext()) {
@ -42,6 +39,9 @@ ScreenWidget::ScreenWidget(ResizeCallback resizeCallback, QWidget* parent) : QWi
} else { } else {
Helpers::panic("Unspported api for Qt screen widget"); Helpers::panic("Unspported api for Qt screen widget");
} }
resize(800, 240 * 4);
show();
} }
void ScreenWidget::resizeEvent(QResizeEvent* event) { void ScreenWidget::resizeEvent(QResizeEvent* event) {