Qt: Start modularizing Qt drawing
Jeffrey Pfau jeffrey@endrift.com
Tue, 31 Mar 2015 22:58:29 -0700
7 files changed,
400 insertions(+),
341 deletions(-)
M
src/platform/qt/CMakeLists.txt
→
src/platform/qt/CMakeLists.txt
@@ -41,6 +41,7 @@ CheatsModel.cpp
CheatsView.cpp ConfigController.cpp Display.cpp + DisplayGL.cpp GBAApp.cpp GBAKeyEditor.cpp GIFView.cpp
M
src/platform/qt/Display.cpp
→
src/platform/qt/Display.cpp
@@ -5,283 +5,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "Display.h" -#include <QApplication> -#include <QResizeEvent> - -extern "C" { -#include "gba/supervisor/thread.h" -} - using namespace QGBA; -static const GLint _glVertices[] = { - 0, 0, - 256, 0, - 256, 256, - 0, 256 -}; - -static const GLint _glTexCoords[] = { - 0, 0, - 1, 0, - 1, 1, - 0, 1 -}; - -Display::Display(QGLFormat format, QWidget* parent) - : QGLWidget(format, parent) - , m_painter(nullptr) - , m_started(false) -{ - setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - setMinimumSize(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); - setAutoBufferSwap(false); - setCursor(Qt::BlankCursor); -} - -void Display::startDrawing(const uint32_t* buffer, GBAThread* thread) { - if (m_started) { - return; - } - m_painter = new Painter(this); - m_painter->setContext(thread); - m_painter->setBacking(buffer); - m_context = thread; - doneCurrent(); - m_painter->start(); - m_started = true; - - lockAspectRatio(m_lockAspectRatio); - filter(m_filter); -} - -void Display::stopDrawing() { - if (m_started) { - if (GBAThreadIsActive(m_context)) { - GBAThreadInterrupt(m_context); - GBASyncSuspendDrawing(&m_context->sync); - } - m_painter->stop(); - m_started = false; - if (GBAThreadIsActive(m_context)) { - GBASyncResumeDrawing(&m_context->sync); - GBAThreadContinue(m_context); - } - } -} - -void Display::pauseDrawing() { - if (m_started) { - if (GBAThreadIsActive(m_context)) { - GBAThreadInterrupt(m_context); - GBASyncSuspendDrawing(&m_context->sync); - } - m_painter->pause(); - if (GBAThreadIsActive(m_context)) { - GBASyncResumeDrawing(&m_context->sync); - GBAThreadContinue(m_context); - } - } -} - -void Display::unpauseDrawing() { - if (m_started) { - if (GBAThreadIsActive(m_context)) { - GBAThreadInterrupt(m_context); - GBASyncSuspendDrawing(&m_context->sync); - } - m_painter->unpause(); - if (GBAThreadIsActive(m_context)) { - GBASyncResumeDrawing(&m_context->sync); - GBAThreadContinue(m_context); - } - } -} - -void Display::forceDraw() { - if (m_started) { - m_painter->forceDraw(); - } -} - -void Display::lockAspectRatio(bool lock) { - m_lockAspectRatio = lock; - if (m_started) { - m_painter->lockAspectRatio(lock); - } -} - -void Display::filter(bool filter) { - m_filter = filter; - if (m_started) { - m_painter->filter(filter); - } -} - -#ifdef USE_PNG -void Display::screenshot() { - GBAThreadInterrupt(m_context); - GBAThreadTakeScreenshot(m_context); - GBAThreadContinue(m_context); -} -#endif - -void Display::initializeGL() { - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - swapBuffers(); -} - -void Display::resizeEvent(QResizeEvent* event) { - if (m_started) { - GBAThreadInterrupt(m_context); - GBASyncSuspendDrawing(&m_context->sync); - m_painter->resize(event->size()); - GBASyncResumeDrawing(&m_context->sync); - GBAThreadContinue(m_context); - } -} - -Painter::Painter(Display* parent) - : m_gl(parent) - , m_lockAspectRatio(false) - , m_filter(false) +Display::Display(QWidget* parent) + : QWidget(parent) { - m_size = parent->size(); -} - -void Painter::setContext(GBAThread* context) { - m_context = context; -} - -void Painter::setBacking(const uint32_t* backing) { - m_backing = backing; -} - -void Painter::resize(const QSize& size) { - m_size = size; - forceDraw(); - forceDraw(); -} - -void Painter::lockAspectRatio(bool lock) { - m_lockAspectRatio = lock; - forceDraw(); - forceDraw(); -} - -void Painter::filter(bool filter) { - m_filter = filter; - m_gl->makeCurrent(); - if (m_filter) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } else { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - m_gl->doneCurrent(); - forceDraw(); -} - -void Painter::start() { - m_gl->makeCurrent(); - glEnable(GL_TEXTURE_2D); - glGenTextures(1, &m_tex); - glBindTexture(GL_TEXTURE_2D, m_tex); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - if (m_filter) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } else { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_INT, 0, _glVertices); - glTexCoordPointer(2, GL_INT, 0, _glTexCoords); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, 240, 160, 0, 0, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - m_gl->doneCurrent(); - - m_drawTimer = new QTimer; - m_drawTimer->moveToThread(QThread::currentThread()); - m_drawTimer->setInterval(0); - connect(m_drawTimer, SIGNAL(timeout()), this, SLOT(draw())); - m_drawTimer->start(); -} - -void Painter::draw() { - m_gl->makeCurrent(); - GBASyncWaitFrameStart(&m_context->sync, m_context->frameskip); - performDraw(); - GBASyncWaitFrameEnd(&m_context->sync); - m_gl->swapBuffers(); - m_gl->doneCurrent(); -} - -void Painter::forceDraw() { - m_gl->makeCurrent(); - glViewport(0, 0, m_size.width() * m_gl->devicePixelRatio(), m_size.height() * m_gl->devicePixelRatio()); - glClear(GL_COLOR_BUFFER_BIT); - performDraw(); - m_gl->swapBuffers(); - m_gl->doneCurrent(); -} - -void Painter::stop() { - m_drawTimer->stop(); - delete m_drawTimer; - m_gl->makeCurrent(); - glDeleteTextures(1, &m_tex); - glClear(GL_COLOR_BUFFER_BIT); - m_gl->swapBuffers(); - m_gl->doneCurrent(); - m_gl->context()->moveToThread(QApplication::instance()->thread()); -} - -void Painter::pause() { - m_drawTimer->stop(); - // Make sure both buffers are filled - forceDraw(); - forceDraw(); -} - -void Painter::unpause() { - m_drawTimer->start(); -} - -void Painter::performDraw() { - int w = m_size.width() * m_gl->devicePixelRatio(); - int h = m_size.height() * m_gl->devicePixelRatio(); -#ifndef Q_OS_MAC - // TODO: This seems to cause framerates to drag down to 120 FPS on OS X, - // even if the emulator can go faster. Look into why. - glViewport(0, 0, m_size.width() * m_gl->devicePixelRatio(), m_size.height() * m_gl->devicePixelRatio()); - glClear(GL_COLOR_BUFFER_BIT); -#endif - int drawW = w; - int drawH = h; - if (m_lockAspectRatio) { - if (w * 2 > h * 3) { - drawW = h * 3 / 2; - } else if (w * 2 < h * 3) { - drawH = w * 2 / 3; - } - } - glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH); -#ifdef COLOR_16_BIT -#ifdef COLOR_5_6_5 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, m_backing); -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, m_backing); -#endif -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_backing); -#endif - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - if (m_context->sync.videoFrameWait) { - glFlush(); - } }
M
src/platform/qt/Display.h
→
src/platform/qt/Display.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014 Jeffrey Pfau +/* Copyright (c) 2013-2015 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this@@ -6,77 +6,29 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef QGBA_DISPLAY #define QGBA_DISPLAY -#include <QGLWidget> -#include <QThread> -#include <QTimer> +#include <QWidget> struct GBAThread; namespace QGBA { -class Painter; -class Display : public QGLWidget { +class Display : public QWidget { Q_OBJECT public: - Display(QGLFormat format, QWidget* parent = nullptr); + Display(QWidget* parent = nullptr); public slots: - void startDrawing(const uint32_t* buffer, GBAThread* context); - void stopDrawing(); - void pauseDrawing(); - void unpauseDrawing(); - void forceDraw(); - void lockAspectRatio(bool lock); - void filter(bool filter); + virtual void startDrawing(const uint32_t* buffer, GBAThread* context) = 0; + virtual void stopDrawing() = 0; + virtual void pauseDrawing() = 0; + virtual void unpauseDrawing() = 0; + virtual void forceDraw() = 0; + virtual void lockAspectRatio(bool lock) = 0; + virtual void filter(bool filter) = 0; #ifdef USE_PNG - void screenshot(); + virtual void screenshot() = 0; #endif - -protected: - virtual void initializeGL() override; - virtual void paintEvent(QPaintEvent*) override {}; - virtual void resizeEvent(QResizeEvent*) override; - -private: - Painter* m_painter; - bool m_started; - GBAThread* m_context; - bool m_lockAspectRatio; - bool m_filter; -}; - -class Painter : public QObject { -Q_OBJECT - -public: - Painter(Display* parent); - - void setContext(GBAThread*); - void setBacking(const uint32_t*); - -public slots: - void forceDraw(); - void draw(); - void start(); - void stop(); - void pause(); - void unpause(); - void resize(const QSize& size); - void lockAspectRatio(bool lock); - void filter(bool filter); - -private: - void performDraw(); - - QTimer* m_drawTimer; - GBAThread* m_context; - const uint32_t* m_backing; - GLuint m_tex; - QGLWidget* m_gl; - QSize m_size; - bool m_lockAspectRatio; - bool m_filter; }; }
A
src/platform/qt/DisplayGL.cpp
@@ -0,0 +1,291 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "DisplayGL.h" + +#include <QApplication> +#include <QResizeEvent> + +extern "C" { +#include "gba/supervisor/thread.h" +} + +using namespace QGBA; + +static const GLint _glVertices[] = { + 0, 0, + 256, 0, + 256, 256, + 0, 256 +}; + +static const GLint _glTexCoords[] = { + 0, 0, + 1, 0, + 1, 1, + 0, 1 +}; + +DisplayGL::DisplayGL(const QGLFormat& format, QWidget* parent) + : Display(parent) + , m_painter(new Painter(format, this)) + , m_started(false) +{ + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + setMinimumSize(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + setCursor(Qt::BlankCursor); +} + +void DisplayGL::startDrawing(const uint32_t* buffer, GBAThread* thread) { + if (m_started) { + return; + } + m_painter->setContext(thread); + m_painter->setBacking(buffer); + m_context = thread; + m_painter->start(); + m_painter->resize(size()); + m_painter->move(0, 0); + m_started = true; + + lockAspectRatio(m_lockAspectRatio); + filter(m_filter); +} + +void DisplayGL::stopDrawing() { + if (m_started) { + if (GBAThreadIsActive(m_context)) { + GBAThreadInterrupt(m_context); + GBASyncSuspendDrawing(&m_context->sync); + } + m_painter->stop(); + m_started = false; + if (GBAThreadIsActive(m_context)) { + GBASyncResumeDrawing(&m_context->sync); + GBAThreadContinue(m_context); + } + } +} + +void DisplayGL::pauseDrawing() { + if (m_started) { + if (GBAThreadIsActive(m_context)) { + GBAThreadInterrupt(m_context); + GBASyncSuspendDrawing(&m_context->sync); + } + m_painter->pause(); + if (GBAThreadIsActive(m_context)) { + GBASyncResumeDrawing(&m_context->sync); + GBAThreadContinue(m_context); + } + } +} + +void DisplayGL::unpauseDrawing() { + if (m_started) { + if (GBAThreadIsActive(m_context)) { + GBAThreadInterrupt(m_context); + GBASyncSuspendDrawing(&m_context->sync); + } + m_painter->unpause(); + if (GBAThreadIsActive(m_context)) { + GBASyncResumeDrawing(&m_context->sync); + GBAThreadContinue(m_context); + } + } +} + +void DisplayGL::forceDraw() { + if (m_started) { + m_painter->forceDraw(); + } +} + +void DisplayGL::lockAspectRatio(bool lock) { + m_lockAspectRatio = lock; + if (m_started) { + m_painter->lockAspectRatio(lock); + } +} + +void DisplayGL::filter(bool filter) { + m_filter = filter; + if (m_started) { + m_painter->filter(filter); + } +} + +#ifdef USE_PNG +void DisplayGL::screenshot() { + GBAThreadInterrupt(m_context); + GBAThreadTakeScreenshot(m_context); + GBAThreadContinue(m_context); +} +#endif + +void DisplayGL::resizeEvent(QResizeEvent* event) { + m_painter->resize(event->size()); +} + +Painter::Painter(const QGLFormat& format, QWidget* parent) + : QGLWidget(format, parent) + , m_drawTimer(nullptr) + , m_lockAspectRatio(false) + , m_filter(false) +{ + setMinimumSize(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + m_size = parent->size(); + setAutoBufferSwap(false); +} + +void Painter::setContext(GBAThread* context) { + m_context = context; +} + +void Painter::setBacking(const uint32_t* backing) { + m_backing = backing; +} + +void Painter::resize(const QSize& size) { + m_size = size; + QWidget::resize(size); + if (m_drawTimer) { + forceDraw(); + forceDraw(); + } +} + +void Painter::lockAspectRatio(bool lock) { + m_lockAspectRatio = lock; + if (m_drawTimer) { + forceDraw(); + forceDraw(); + } +} + +void Painter::filter(bool filter) { + m_filter = filter; + makeCurrent(); + if (m_filter) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } else { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + doneCurrent(); + if (m_drawTimer) { + forceDraw(); + forceDraw(); + } +} + +void Painter::start() { + makeCurrent(); + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &m_tex); + glBindTexture(GL_TEXTURE_2D, m_tex); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (m_filter) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } else { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, GL_INT, 0, _glVertices); + glTexCoordPointer(2, GL_INT, 0, _glTexCoords); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, 240, 160, 0, 0, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + doneCurrent(); + + m_drawTimer = new QTimer; + m_drawTimer->moveToThread(QThread::currentThread()); + m_drawTimer->setInterval(0); + connect(m_drawTimer, SIGNAL(timeout()), this, SLOT(draw())); + m_drawTimer->start(); +} + +void Painter::draw() { + makeCurrent(); + GBASyncWaitFrameStart(&m_context->sync, m_context->frameskip); + performDraw(); + GBASyncWaitFrameEnd(&m_context->sync); + swapBuffers(); + doneCurrent(); +} + +void Painter::forceDraw() { + makeCurrent(); + glViewport(0, 0, m_size.width() * devicePixelRatio(), m_size.height() * devicePixelRatio()); + glClear(GL_COLOR_BUFFER_BIT); + performDraw(); + swapBuffers(); + doneCurrent(); +} + +void Painter::stop() { + m_drawTimer->stop(); + delete m_drawTimer; + m_drawTimer = nullptr; + makeCurrent(); + glDeleteTextures(1, &m_tex); + glClear(GL_COLOR_BUFFER_BIT); + swapBuffers(); + doneCurrent(); +} + +void Painter::pause() { + m_drawTimer->stop(); + // Make sure both buffers are filled + forceDraw(); + forceDraw(); +} + +void Painter::unpause() { + m_drawTimer->start(); +} + +void Painter::initializeGL() { + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + swapBuffers(); +} + +void Painter::performDraw() { + int w = m_size.width() * devicePixelRatio(); + int h = m_size.height() * devicePixelRatio(); +#ifndef Q_OS_MAC + // TODO: This seems to cause framerates to drag down to 120 FPS on OS X, + // even if the emulator can go faster. Look into why. + glViewport(0, 0, m_size.width() * devicePixelRatio(), m_size.height() * devicePixelRatio()); + glClear(GL_COLOR_BUFFER_BIT); +#endif + int drawW = w; + int drawH = h; + if (m_lockAspectRatio) { + if (w * 2 > h * 3) { + drawW = h * 3 / 2; + } else if (w * 2 < h * 3) { + drawH = w * 2 / 3; + } + } + glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH); +#ifdef COLOR_16_BIT +#ifdef COLOR_5_6_5 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, m_backing); +#else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, m_backing); +#endif +#else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_backing); +#endif + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + if (m_context->sync.videoFrameWait) { + glFlush(); + } +}
A
src/platform/qt/DisplayGL.h
@@ -0,0 +1,87 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef QGBA_DISPLAY_GL +#define QGBA_DISPLAY_GL + +#include "Display.h" + +#include <QGLWidget> +#include <QThread> +#include <QTimer> + +struct GBAThread; + +namespace QGBA { + +class Painter; +class DisplayGL : public Display { +Q_OBJECT + +public: + DisplayGL(const QGLFormat& format, QWidget* parent = nullptr); + +public slots: + void startDrawing(const uint32_t* buffer, GBAThread* context); + void stopDrawing(); + void pauseDrawing(); + void unpauseDrawing(); + void forceDraw(); + void lockAspectRatio(bool lock); + void filter(bool filter); +#ifdef USE_PNG + void screenshot(); +#endif + +protected: + virtual void paintEvent(QPaintEvent*) override {}; + virtual void resizeEvent(QResizeEvent*) override; + +private: + Painter* m_painter; + bool m_started; + GBAThread* m_context; + bool m_lockAspectRatio; + bool m_filter; +}; + +class Painter : public QGLWidget { +Q_OBJECT + +public: + Painter(const QGLFormat& format, QWidget* parent); + + void setContext(GBAThread*); + void setBacking(const uint32_t*); + +public slots: + void forceDraw(); + void draw(); + void start(); + void stop(); + void pause(); + void unpause(); + void resize(const QSize& size); + void lockAspectRatio(bool lock); + void filter(bool filter); + +protected: + virtual void initializeGL() override; + +private: + void performDraw(); + + QTimer* m_drawTimer; + GBAThread* m_context; + const uint32_t* m_backing; + GLuint m_tex; + QSize m_size; + bool m_lockAspectRatio; + bool m_filter; +}; + +} + +#endif
M
src/platform/qt/Window.cpp
→
src/platform/qt/Window.cpp
@@ -16,6 +16,7 @@ #include <QStackedLayout>
#include "CheatsView.h" #include "ConfigController.h" +#include "DisplayGL.h" #include "GameController.h" #include "GBAKeyEditor.h" #include "GDBController.h"@@ -67,7 +68,7 @@ m_controller->setOverrides(m_config->overrides());
QGLFormat format(QGLFormat(QGL::Rgba | QGL::DoubleBuffer)); format.setSwapInterval(1); - m_display = new Display(format); + m_display = new DisplayGL(format); m_logo.setDevicePixelRatio(m_screenWidget->devicePixelRatio()); m_logo = m_logo; // Free memory left over in old pixmap@@ -857,6 +858,7 @@ }
} void Window::attachWidget(QWidget* widget) { + m_screenWidget->clear(); m_screenWidget->layout()->addWidget(widget); static_cast<QStackedLayout*>(m_screenWidget->layout())->setCurrentWidget(widget); }@@ -924,13 +926,13 @@ m_aspectHeight = height;
} void WindowBackground::paintEvent(QPaintEvent*) { - QPainter painter(this); - painter.setRenderHint(QPainter::SmoothPixmapTransform); const QPixmap* logo = pixmap(); - painter.fillRect(QRect(QPoint(), size()), Qt::black); if (!logo) { return; } + QPainter painter(this); + painter.setRenderHint(QPainter::SmoothPixmapTransform); + painter.fillRect(QRect(QPoint(), size()), Qt::black); QSize s = size(); QSize ds = s; if (s.width() * m_aspectHeight > s.height() * m_aspectWidth) {
M
src/platform/qt/Window.h
→
src/platform/qt/Window.h
@@ -18,7 +18,6 @@ #include "gba/gba.h"
} #include "GDBController.h" -#include "Display.h" #include "InputController.h" #include "LoadSaveState.h"@@ -28,6 +27,7 @@
namespace QGBA { class ConfigController; +class Display; class GameController; class GIFView; class LogView;