From 42813bb197dee028b64ba70b0a9b63aea2cf264c Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 10 May 2019 11:12:24 -0700 Subject: [PATCH 01/44] Qt: Add VideoProxy --- include/mgba/core/core.h | 1 + src/gba/core.c | 10 +++- src/platform/qt/CMakeLists.txt | 1 + src/platform/qt/Display.h | 2 + src/platform/qt/DisplayGL.cpp | 18 +++++-- src/platform/qt/DisplayGL.h | 7 ++- src/platform/qt/VideoProxy.cpp | 97 ++++++++++++++++++++++++++++++++++ src/platform/qt/VideoProxy.h | 68 ++++++++++++++++++++++++ src/platform/qt/Window.cpp | 12 +++-- 9 files changed, 207 insertions(+), 9 deletions(-) create mode 100644 src/platform/qt/VideoProxy.cpp create mode 100644 src/platform/qt/VideoProxy.h diff --git a/include/mgba/core/core.h b/include/mgba/core/core.h index 569b55f82..fe08ae0cd 100644 --- a/include/mgba/core/core.h +++ b/include/mgba/core/core.h @@ -47,6 +47,7 @@ struct mCore { struct mTiming* timing; struct mDebugger* debugger; struct mDebuggerSymbols* symbolTable; + struct mVideoLogger* videoLogger; #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 struct mDirectorySet dirs; diff --git a/src/gba/core.c b/src/gba/core.c index 8966fbe37..95d217ac6 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -151,6 +151,7 @@ static bool _GBACoreInit(struct mCore* core) { core->timing = &gba->timing; core->debugger = NULL; core->symbolTable = NULL; + core->videoLogger = NULL; gbacore->overrides = NULL; gbacore->debuggerPlatform = NULL; gbacore->cheatDevice = NULL; @@ -392,11 +393,16 @@ static void _GBACoreReset(struct mCore* core) { #ifndef DISABLE_THREADING int fakeBool; if (mCoreConfigGetIntValue(&core->config, "threadedVideo", &fakeBool) && fakeBool) { - gbacore->proxyRenderer.logger = &gbacore->threadProxy.d; + if (!core->videoLogger) { + core->videoLogger = &gbacore->threadProxy.d; + } + } +#endif + if (core->videoLogger) { + gbacore->proxyRenderer.logger = core->videoLogger; GBAVideoProxyRendererCreate(&gbacore->proxyRenderer, renderer); renderer = &gbacore->proxyRenderer.d; } -#endif GBAVideoAssociateRenderer(&gba->video, renderer); } diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index 76d21a241..9b3eb63f0 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -121,6 +121,7 @@ set(SOURCE_FILES utils.cpp Window.cpp VFileDevice.cpp + VideoProxy.cpp VideoView.cpp) set(UI_FILES diff --git a/src/platform/qt/Display.h b/src/platform/qt/Display.h index 76816ec47..de8c03648 100644 --- a/src/platform/qt/Display.h +++ b/src/platform/qt/Display.h @@ -19,6 +19,7 @@ struct VideoShader; namespace QGBA { class CoreController; +class VideoProxy; class Display : public QWidget { Q_OBJECT @@ -47,6 +48,7 @@ public: virtual bool isDrawing() const = 0; virtual bool supportsShaders() const = 0; virtual VideoShader* shaders() = 0; + virtual VideoProxy* videoProxy() { return nullptr; } signals: void showCursor(); diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index 62166ec5d..b7af84b25 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -34,10 +34,12 @@ DisplayGL::DisplayGL(const QGLFormat& format, QWidget* parent) // This can spontaneously re-enter into this->resizeEvent before creation is done, so we // need to make sure it's initialized to nullptr before we assign the new object to it m_gl = new EmptyGLWidget(format, this); - m_painter = new PainterGL(format.majorVersion() < 2 ? 1 : m_gl->format().majorVersion(), m_gl); + m_painter = new PainterGL(format.majorVersion() < 2 ? 1 : m_gl->format().majorVersion(), &m_videoProxy, m_gl); m_gl->setMouseTracking(true); m_gl->setAttribute(Qt::WA_TransparentForMouseEvents); // This doesn't seem to work? setUpdatesEnabled(false); // Prevent paint events, which can cause race conditions + + connect(&m_videoProxy, &VideoProxy::dataAvailable, &m_videoProxy, &VideoProxy::processData); } DisplayGL::~DisplayGL() { @@ -74,6 +76,7 @@ void DisplayGL::startDrawing(std::shared_ptr controller) { m_gl->context()->doneCurrent(); m_gl->context()->moveToThread(m_drawThread); m_painter->moveToThread(m_drawThread); + m_videoProxy.moveToThread(m_drawThread); connect(m_drawThread, &QThread::started, m_painter, &PainterGL::start); m_drawThread->start(); @@ -184,8 +187,16 @@ void DisplayGL::resizePainter() { } } -PainterGL::PainterGL(int majorVersion, QGLWidget* parent) +VideoProxy* DisplayGL::videoProxy() { + if (supportsShaders()) { + return &m_videoProxy; + } + return nullptr; +} + +PainterGL::PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent) : m_gl(parent) + , m_videoProxy(proxy) { #ifdef BUILD_GL mGLContext* glBackend; @@ -347,7 +358,7 @@ void PainterGL::draw() { m_backend->swap(m_backend); if (!m_delayTimer.isValid()) { m_delayTimer.start(); - } else { + } else if (m_gl->format().swapInterval()) { while (m_delayTimer.elapsed() < 15) { QThread::usleep(100); } @@ -382,6 +393,7 @@ void PainterGL::stop() { m_gl->context()->moveToThread(m_gl->thread()); m_context.reset(); moveToThread(m_gl->thread()); + m_videoProxy->moveToThread(m_gl->thread()); } void PainterGL::pause() { diff --git a/src/platform/qt/DisplayGL.h b/src/platform/qt/DisplayGL.h index fbf44a547..8ef6f9e1c 100644 --- a/src/platform/qt/DisplayGL.h +++ b/src/platform/qt/DisplayGL.h @@ -23,6 +23,8 @@ #include #include +#include "VideoProxy.h" + #include "platform/video-backend.h" namespace QGBA { @@ -49,6 +51,7 @@ public: bool isDrawing() const override { return m_isDrawing; } bool supportsShaders() const override; VideoShader* shaders() override; + VideoProxy* videoProxy() override; public slots: void stopDrawing() override; @@ -75,13 +78,14 @@ private: PainterGL* m_painter; QThread* m_drawThread = nullptr; std::shared_ptr m_context; + VideoProxy m_videoProxy; }; class PainterGL : public QObject { Q_OBJECT public: - PainterGL(int majorVersion, QGLWidget* parent); + PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent); ~PainterGL(); void setContext(std::shared_ptr); @@ -126,6 +130,7 @@ private: QSize m_size; MessagePainter* m_messagePainter = nullptr; QElapsedTimer m_delayTimer; + VideoProxy* m_videoProxy; }; } diff --git a/src/platform/qt/VideoProxy.cpp b/src/platform/qt/VideoProxy.cpp new file mode 100644 index 000000000..0c378f59c --- /dev/null +++ b/src/platform/qt/VideoProxy.cpp @@ -0,0 +1,97 @@ +/* Copyright (c) 2013-2018 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 "VideoProxy.h" + +#include "CoreController.h" + +using namespace QGBA; + +VideoProxy::VideoProxy() { + mVideoLoggerRendererCreate(&m_logger.d, false); + m_logger.d.block = true; + + m_logger.d.init = &cbind<&VideoProxy::init>; + m_logger.d.reset = &cbind<&VideoProxy::reset>; + m_logger.d.deinit = &cbind<&VideoProxy::deinit>; + m_logger.d.lock = &cbind<&VideoProxy::lock>; + m_logger.d.unlock = &cbind<&VideoProxy::unlock>; + m_logger.d.wait = &cbind<&VideoProxy::wait>; + m_logger.d.wake = &callback::func<&VideoProxy::wake>; + + m_logger.d.writeData = &callback::func<&VideoProxy::writeData>; + m_logger.d.readData = &callback::func<&VideoProxy::readData>; +} + +void VideoProxy::attach(CoreController* controller) { + CoreController::Interrupter interrupter(controller); + controller->thread()->core->videoLogger = &m_logger.d; +} + +void VideoProxy::processData() { + mVideoLoggerRendererRun(&m_logger.d, false); + m_fromThreadCond.wakeAll(); +} + +void VideoProxy::init() { + RingFIFOInit(&m_dirtyQueue, 0x80000); +} + +void VideoProxy::reset() { + RingFIFOClear(&m_dirtyQueue); +} + +void VideoProxy::deinit() { + RingFIFODeinit(&m_dirtyQueue); +} + +bool VideoProxy::writeData(const void* data, size_t length) { + while (!RingFIFOWrite(&m_dirtyQueue, data, length)) { + emit dataAvailable(); + m_mutex.lock(); + m_toThreadCond.wakeAll(); + m_fromThreadCond.wait(&m_mutex); + m_mutex.unlock(); + } + emit dataAvailable(); + return true; +} + +bool VideoProxy::readData(void* data, size_t length, bool block) { + bool read = false; + while (true) { + read = RingFIFORead(&m_dirtyQueue, data, length); + if (!block || read) { + break; + } + m_mutex.lock(); + m_fromThreadCond.wakeAll(); + m_toThreadCond.wait(&m_mutex); + m_mutex.unlock(); + } + return read; +} + +void VideoProxy::lock() { + m_mutex.lock(); +} + +void VideoProxy::unlock() { + m_mutex.unlock(); +} + +void VideoProxy::wait() { + while (RingFIFOSize(&m_dirtyQueue)) { + emit dataAvailable(); + m_toThreadCond.wakeAll(); + m_fromThreadCond.wait(&m_mutex, 1); + } +} + +void VideoProxy::wake(int y) { + if ((y & 15) == 15) { + m_toThreadCond.wakeAll(); + } +} diff --git a/src/platform/qt/VideoProxy.h b/src/platform/qt/VideoProxy.h new file mode 100644 index 000000000..d686478c0 --- /dev/null +++ b/src/platform/qt/VideoProxy.h @@ -0,0 +1,68 @@ +/* Copyright (c) 2013-2018 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/. */ +#pragma once + +#include +#include +#include + +#include +#include + +namespace QGBA { + +class CoreController; + +class VideoProxy : public QObject { +Q_OBJECT + +public: + VideoProxy(); + + void attach(CoreController*); + +signals: + void dataAvailable(); + +public slots: + void processData(); + +private: + void init(); + void reset(); + void deinit(); + + bool writeData(const void* data, size_t length); + bool readData(void* data, size_t length, bool block); + + void lock(); + void unlock(); + void wait(); + void wake(int y); + + template struct callback { + using type = T (VideoProxy::*)(A...); + + template static T func(mVideoLogger* logger, A... args) { + VideoProxy* proxy = reinterpret_cast(logger)->p; + return (proxy->*F)(args...); + } + }; + + template static void cbind(mVideoLogger* logger) { callback::func(logger); } + + struct Logger { + mVideoLogger d; + VideoProxy* p; + } m_logger = {{}, this}; + + RingFIFO m_dirtyQueue; + QMutex m_mutex; + QWaitCondition m_toThreadCond; + QWaitCondition m_fromThreadCond; +}; + +} \ No newline at end of file diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index d6821795c..379f5cecb 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -52,6 +52,7 @@ #include "ShaderSelector.h" #include "ShortcutController.h" #include "TileView.h" +#include "VideoProxy.h" #include "VideoView.h" #ifdef USE_DISCORD_RPC @@ -716,9 +717,6 @@ void Window::gameStarted() { if (m_savedScale > 0) { resizeFrame(size * m_savedScale); } - if (!m_display) { - reloadDisplayDriver(); - } attachWidget(m_display.get()); m_display->setMinimumSize(size); setFocus(); @@ -1713,6 +1711,14 @@ void Window::setController(CoreController* controller, const QString& fname) { appendMRU(fname); } + if (!m_display) { + reloadDisplayDriver(); + } + + if (m_display->videoProxy()) { + m_display->videoProxy()->attach(controller); + } + m_controller = std::shared_ptr(controller); m_inputController.recalibrateAxes(); m_controller->setInputController(&m_inputController); From 82ef919ee27e93f684d260dd147f71f601806b64 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 10 May 2019 11:13:21 -0700 Subject: [PATCH 02/44] Feature: More video logging plumbing --- include/mgba/feature/thread-proxy.h | 1 + include/mgba/feature/video-logger.h | 9 +++++++ src/feature/thread-proxy.c | 27 ++++++++++++++++----- src/gba/extra/proxy.c | 37 ++++++++++++++++++++++++++--- src/platform/qt/DisplayGL.cpp | 1 + src/platform/qt/VideoProxy.cpp | 9 +++++++ src/platform/qt/VideoProxy.h | 3 +++ 7 files changed, 78 insertions(+), 9 deletions(-) diff --git a/include/mgba/feature/thread-proxy.h b/include/mgba/feature/thread-proxy.h index cb663d506..36f432b03 100644 --- a/include/mgba/feature/thread-proxy.h +++ b/include/mgba/feature/thread-proxy.h @@ -29,6 +29,7 @@ struct mVideoThreadProxy { Condition toThreadCond; Mutex mutex; enum mVideoThreadProxyState threadState; + enum mVideoLoggerEvent event; struct RingFIFO dirtyQueue; }; diff --git a/include/mgba/feature/video-logger.h b/include/mgba/feature/video-logger.h index f194433a2..bae94157a 100644 --- a/include/mgba/feature/video-logger.h +++ b/include/mgba/feature/video-logger.h @@ -27,6 +27,13 @@ enum mVideoLoggerDirtyType { DIRTY_BUFFER, }; +enum mVideoLoggerEvent { + LOGGER_EVENT_NONE = 0, + LOGGER_EVENT_INIT, + LOGGER_EVENT_DEINIT, + LOGGER_EVENT_RESET, +}; + struct mVideoLoggerDirtyInfo { enum mVideoLoggerDirtyType type; uint32_t address; @@ -38,6 +45,7 @@ struct VFile; struct mVideoLogger { bool (*writeData)(struct mVideoLogger* logger, const void* data, size_t length); bool (*readData)(struct mVideoLogger* logger, void* data, size_t length, bool block); + void (*postEvent)(struct mVideoLogger* logger, enum mVideoLoggerEvent event); void* dataContext; bool block; @@ -52,6 +60,7 @@ struct mVideoLogger { void* context; bool (*parsePacket)(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* packet); + void (*handleEvent)(struct mVideoLogger* logger, enum mVideoLoggerEvent event); uint16_t* (*vramBlock)(struct mVideoLogger* logger, uint32_t address); size_t vramSize; diff --git a/src/feature/thread-proxy.c b/src/feature/thread-proxy.c index d00da8cd8..7a67dbedd 100644 --- a/src/feature/thread-proxy.c +++ b/src/feature/thread-proxy.c @@ -18,6 +18,7 @@ static THREAD_ENTRY _proxyThread(void* renderer); static bool _writeData(struct mVideoLogger* logger, const void* data, size_t length); static bool _readData(struct mVideoLogger* logger, void* data, size_t length, bool block); +static void _postEvent(struct mVideoLogger* logger, enum mVideoLoggerEvent); static void _lock(struct mVideoLogger* logger); static void _unlock(struct mVideoLogger* logger); @@ -38,6 +39,7 @@ void mVideoThreadProxyCreate(struct mVideoThreadProxy* renderer) { renderer->d.writeData = _writeData; renderer->d.readData = _readData; + renderer->d.postEvent = _postEvent; } void mVideoThreadProxyInit(struct mVideoLogger* logger) { @@ -131,6 +133,14 @@ static bool _readData(struct mVideoLogger* logger, void* data, size_t length, bo return read; } +static void _postEvent(struct mVideoLogger* logger, enum mVideoLoggerEvent event) { + struct mVideoThreadProxy* proxyRenderer = (struct mVideoThreadProxy*) logger; + MutexLock(&proxyRenderer->mutex); + proxyRenderer->event = event; + ConditionWake(&proxyRenderer->toThreadCond); + MutexUnlock(&proxyRenderer->mutex); +} + static void _lock(struct mVideoLogger* logger) { struct mVideoThreadProxy* proxyRenderer = (struct mVideoThreadProxy*) logger; MutexLock(&proxyRenderer->mutex); @@ -172,13 +182,18 @@ static THREAD_ENTRY _proxyThread(void* logger) { break; } proxyRenderer->threadState = PROXY_THREAD_BUSY; - MutexUnlock(&proxyRenderer->mutex); - if (!mVideoLoggerRendererRun(&proxyRenderer->d, false)) { - // FIFO was corrupted - proxyRenderer->threadState = PROXY_THREAD_STOPPED; - mLOG(GBA_VIDEO, ERROR, "Proxy thread queue got corrupted!"); + if (proxyRenderer->event) { + proxyRenderer->d.handleEvent(&proxyRenderer->d, proxyRenderer->event); + proxyRenderer->event = 0; + } else { + MutexUnlock(&proxyRenderer->mutex); + if (!mVideoLoggerRendererRun(&proxyRenderer->d, false)) { + // FIFO was corrupted + proxyRenderer->threadState = PROXY_THREAD_STOPPED; + mLOG(GBA_VIDEO, ERROR, "Proxy thread queue got corrupted!"); + } + MutexLock(&proxyRenderer->mutex); } - MutexLock(&proxyRenderer->mutex); ConditionWake(&proxyRenderer->fromThreadCond); if (proxyRenderer->threadState != PROXY_THREAD_STOPPED) { proxyRenderer->threadState = PROXY_THREAD_IDLE; diff --git a/src/gba/extra/proxy.c b/src/gba/extra/proxy.c index deeec5603..ea884db3b 100644 --- a/src/gba/extra/proxy.c +++ b/src/gba/extra/proxy.c @@ -21,6 +21,7 @@ static void GBAVideoProxyRendererFinishFrame(struct GBAVideoRenderer* renderer); static void GBAVideoProxyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels); static void GBAVideoProxyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels); +static void _handleEvent(struct mVideoLogger* logger, enum mVideoLoggerEvent event); static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* packet); static uint16_t* _vramBlock(struct mVideoLogger* logger, uint32_t address); @@ -45,6 +46,7 @@ void GBAVideoProxyRendererCreate(struct GBAVideoProxyRenderer* renderer, struct renderer->logger->context = renderer; renderer->logger->parsePacket = _parsePacket; + renderer->logger->handleEvent = _handleEvent; renderer->logger->vramBlock = _vramBlock; renderer->logger->paletteSize = SIZE_PALETTE_RAM; renderer->logger->vramSize = SIZE_VRAM; @@ -105,7 +107,11 @@ void GBAVideoProxyRendererInit(struct GBAVideoRenderer* renderer) { _init(proxyRenderer); _reset(proxyRenderer); - proxyRenderer->backend->init(proxyRenderer->backend); + if (!proxyRenderer->logger->block) { + proxyRenderer->backend->init(proxyRenderer->backend); + } else { + proxyRenderer->logger->postEvent(proxyRenderer->logger, LOGGER_EVENT_INIT); + } } void GBAVideoProxyRendererReset(struct GBAVideoRenderer* renderer) { @@ -113,17 +119,42 @@ void GBAVideoProxyRendererReset(struct GBAVideoRenderer* renderer) { _reset(proxyRenderer); - proxyRenderer->backend->reset(proxyRenderer->backend); + if (!proxyRenderer->logger->block) { + proxyRenderer->backend->reset(proxyRenderer->backend); + } else { + proxyRenderer->logger->postEvent(proxyRenderer->logger, LOGGER_EVENT_RESET); + } } void GBAVideoProxyRendererDeinit(struct GBAVideoRenderer* renderer) { struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer; - proxyRenderer->backend->deinit(proxyRenderer->backend); + if (!proxyRenderer->logger->block) { + proxyRenderer->backend->deinit(proxyRenderer->backend); + } else { + proxyRenderer->logger->postEvent(proxyRenderer->logger, LOGGER_EVENT_DEINIT); + } mVideoLoggerRendererDeinit(proxyRenderer->logger); } +static void _handleEvent(struct mVideoLogger* logger, enum mVideoLoggerEvent event) { + struct GBAVideoProxyRenderer* proxyRenderer = logger->context; + switch (event) { + default: + break; + case LOGGER_EVENT_INIT: + proxyRenderer->backend->init(proxyRenderer->backend); + break; + case LOGGER_EVENT_DEINIT: + proxyRenderer->backend->deinit(proxyRenderer->backend); + break; + case LOGGER_EVENT_RESET: + proxyRenderer->backend->reset(proxyRenderer->backend); + break; + } +} + static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* item) { struct GBAVideoProxyRenderer* proxyRenderer = logger->context; switch (item->type) { diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index b7af84b25..c7374f274 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -40,6 +40,7 @@ DisplayGL::DisplayGL(const QGLFormat& format, QWidget* parent) setUpdatesEnabled(false); // Prevent paint events, which can cause race conditions connect(&m_videoProxy, &VideoProxy::dataAvailable, &m_videoProxy, &VideoProxy::processData); + connect(&m_videoProxy, &VideoProxy::eventPosted, &m_videoProxy, &VideoProxy::handleEvent); } DisplayGL::~DisplayGL() { diff --git a/src/platform/qt/VideoProxy.cpp b/src/platform/qt/VideoProxy.cpp index 0c378f59c..a6c673207 100644 --- a/src/platform/qt/VideoProxy.cpp +++ b/src/platform/qt/VideoProxy.cpp @@ -23,6 +23,7 @@ VideoProxy::VideoProxy() { m_logger.d.writeData = &callback::func<&VideoProxy::writeData>; m_logger.d.readData = &callback::func<&VideoProxy::readData>; + m_logger.d.postEvent = &callback::func<&VideoProxy::postEvent>; } void VideoProxy::attach(CoreController* controller) { @@ -74,6 +75,14 @@ bool VideoProxy::readData(void* data, size_t length, bool block) { return read; } +void VideoProxy::postEvent(enum mVideoLoggerEvent event) { + emit eventPosted(event); +} + +void VideoProxy::handleEvent(int event) { + m_logger.d.handleEvent(&m_logger.d, static_cast(event)); +} + void VideoProxy::lock() { m_mutex.lock(); } diff --git a/src/platform/qt/VideoProxy.h b/src/platform/qt/VideoProxy.h index d686478c0..7f778a605 100644 --- a/src/platform/qt/VideoProxy.h +++ b/src/platform/qt/VideoProxy.h @@ -26,9 +26,11 @@ public: signals: void dataAvailable(); + void eventPosted(int); public slots: void processData(); + void handleEvent(int); private: void init(); @@ -37,6 +39,7 @@ private: bool writeData(const void* data, size_t length); bool readData(void* data, size_t length, bool block); + void postEvent(enum mVideoLoggerEvent event); void lock(); void unlock(); From 618ddac38731b79933b7d39d4c1b50342d011d73 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 10 May 2019 11:14:37 -0700 Subject: [PATCH 03/44] GBA Video: Start GL renderer --- src/gba/core.c | 9 +++- src/gba/renderers/gl.c | 90 +++++++++++++++++++++++++++++++++++ src/platform/qt/DisplayGL.cpp | 36 ++++++++------ 3 files changed, 120 insertions(+), 15 deletions(-) create mode 100644 src/gba/renderers/gl.c diff --git a/src/gba/core.c b/src/gba/core.c index 95d217ac6..358b9882e 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -17,6 +17,7 @@ #ifndef DISABLE_THREADING #include #endif +#include #include #include #include @@ -123,6 +124,7 @@ struct mVideoLogContext; struct GBACore { struct mCore d; struct GBAVideoSoftwareRenderer renderer; + struct GBAVideoGLRenderer glRenderer; struct GBAVideoProxyRenderer proxyRenderer; struct mVideoLogContext* logContext; struct mCoreCallbacks logCallbacks; @@ -166,6 +168,7 @@ static bool _GBACoreInit(struct mCore* core) { gba->rtcSource = &core->rtc.d; GBAVideoSoftwareRendererCreate(&gbacore->renderer); + GBAVideoGLRendererCreate(&gbacore->glRenderer); gbacore->renderer.outputBuffer = NULL; #ifndef DISABLE_THREADING @@ -251,6 +254,7 @@ static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* con #ifndef DISABLE_THREADING mCoreConfigCopyValue(&core->config, config, "threadedVideo"); #endif + mCoreConfigCopyValue(&core->config, config, "hwaccelVideo"); } static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) { @@ -390,14 +394,17 @@ static void _GBACoreReset(struct mCore* core) { struct GBA* gba = (struct GBA*) core->board; if (gbacore->renderer.outputBuffer) { struct GBAVideoRenderer* renderer = &gbacore->renderer.d; -#ifndef DISABLE_THREADING int fakeBool; +#ifndef DISABLE_THREADING if (mCoreConfigGetIntValue(&core->config, "threadedVideo", &fakeBool) && fakeBool) { if (!core->videoLogger) { core->videoLogger = &gbacore->threadProxy.d; } } #endif + if (mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) { + renderer = &gbacore->glRenderer.d; + } if (core->videoLogger) { gbacore->proxyRenderer.logger = core->videoLogger; GBAVideoProxyRendererCreate(&gbacore->proxyRenderer, renderer); diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c new file mode 100644 index 000000000..54fb85a1f --- /dev/null +++ b/src/gba/renderers/gl.c @@ -0,0 +1,90 @@ +/* Copyright (c) 2013-2019 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 + +#include +#include +#include +#include + +static void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer); +static void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer); +static void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer); +static void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address); +static void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam); +static void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value); +static uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value); +static void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y); +static void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer); +static void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels); +static void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels); + +void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) { + renderer->d.init = GBAVideoGLRendererInit; + renderer->d.reset = GBAVideoGLRendererReset; + renderer->d.deinit = GBAVideoGLRendererDeinit; + renderer->d.writeVideoRegister = GBAVideoGLRendererWriteVideoRegister; + renderer->d.writeVRAM = GBAVideoGLRendererWriteVRAM; + renderer->d.writeOAM = GBAVideoGLRendererWriteOAM; + renderer->d.writePalette = GBAVideoGLRendererWritePalette; + renderer->d.drawScanline = GBAVideoGLRendererDrawScanline; + renderer->d.finishFrame = GBAVideoGLRendererFinishFrame; + renderer->d.getPixels = GBAVideoGLRendererGetPixels; + renderer->d.putPixels = GBAVideoGLRendererPutPixels; + + renderer->d.disableBG[0] = false; + renderer->d.disableBG[1] = false; + renderer->d.disableBG[2] = false; + renderer->d.disableBG[3] = false; + renderer->d.disableOBJ = false; + + renderer->temporaryBuffer = 0; +} + +void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { + +} + +void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { + +} + +void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) { + +} + +void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) { + +} + +void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) { + +} + +void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) { + +} + +uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) { + +} + +void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { + +} + +void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) { + +} + +void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) { + +} + +void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) { + +} + diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index c7374f274..722359255 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -287,13 +287,18 @@ void PainterGL::resizeContext() { return; } - m_gl->makeCurrent(); + if (!m_active) { + m_gl->makeCurrent(); #if defined(_WIN32) && defined(USE_EPOXY) - epoxy_handle_external_wglMakeCurrent(); + epoxy_handle_external_wglMakeCurrent(); #endif + } + QSize size = m_context->screenDimensions(); m_backend->setDimensions(m_backend, size.width(), size.height()); - m_gl->doneCurrent(); + if (!m_active) { + m_gl->doneCurrent(); + } } void PainterGL::setMessagePainter(MessagePainter* messagePainter) { @@ -340,7 +345,6 @@ void PainterGL::start() { } #endif - m_gl->doneCurrent(); m_active = true; m_started = true; } @@ -383,10 +387,6 @@ void PainterGL::forceDraw() { void PainterGL::stop() { m_active = false; m_started = false; - m_gl->makeCurrent(); -#if defined(_WIN32) && defined(USE_EPOXY) - epoxy_handle_external_wglMakeCurrent(); -#endif dequeueAll(); m_backend->clear(m_backend); m_backend->swap(m_backend); @@ -463,11 +463,13 @@ void PainterGL::setShaders(struct VDir* dir) { if (!supportsShaders()) { return; } + if (!m_active) { #if !defined(_WIN32) || defined(USE_EPOXY) - m_gl->makeCurrent(); + m_gl->makeCurrent(); #if defined(_WIN32) && defined(USE_EPOXY) - epoxy_handle_external_wglMakeCurrent(); + epoxy_handle_external_wglMakeCurrent(); #endif + } if (m_shader.passes) { mGLES2ShaderDetach(reinterpret_cast(m_backend)); mGLES2ShaderFree(&m_shader); @@ -476,7 +478,9 @@ void PainterGL::setShaders(struct VDir* dir) { if (m_started) { mGLES2ShaderAttach(reinterpret_cast(m_backend), static_cast(m_shader.passes), m_shader.nPasses); } - m_gl->doneCurrent(); + if (!m_active) { + m_gl->doneCurrent(); + } #endif } @@ -484,16 +488,20 @@ void PainterGL::clearShaders() { if (!supportsShaders()) { return; } + if (!m_active) { #if !defined(_WIN32) || defined(USE_EPOXY) - m_gl->makeCurrent(); + m_gl->makeCurrent(); #if defined(_WIN32) && defined(USE_EPOXY) - epoxy_handle_external_wglMakeCurrent(); + epoxy_handle_external_wglMakeCurrent(); #endif + } if (m_shader.passes) { mGLES2ShaderDetach(reinterpret_cast(m_backend)); mGLES2ShaderFree(&m_shader); } - m_gl->doneCurrent(); + if (!m_active) { + m_gl->doneCurrent(); + } #endif } From f5d9e9ec5bcca9f5c8fbc573f14f7005efb4f81e Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 8 May 2019 20:43:55 -0700 Subject: [PATCH 04/44] GBA Video: Begin fleshing out GL renderer --- src/gba/core.c | 2 + src/gba/renderers/gl.c | 109 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 106 insertions(+), 5 deletions(-) diff --git a/src/gba/core.c b/src/gba/core.c index 358b9882e..0edd73b85 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -267,6 +267,8 @@ static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t s struct GBACore* gbacore = (struct GBACore*) core; gbacore->renderer.outputBuffer = buffer; gbacore->renderer.outputBufferStride = stride; + gbacore->glRenderer.outputBuffer = buffer; + gbacore->glRenderer.outputBufferStride = stride; memset(gbacore->renderer.scanlineDirty, 0xFFFFFFFF, sizeof(gbacore->renderer.scanlineDirty)); } diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 54fb85a1f..4a7fab348 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -22,6 +22,35 @@ static void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer); static void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels); static void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels); +static const GLchar* const _gl3Header = + "#version 120\n"; + +static const char* const _vertexShader = + "attribute vec4 position;\n" + "varying vec2 texCoord;\n" + + "void main() {\n" + " gl_Position = position;\n" + " texCoord = (position.st + vec2(1.0, -1.0)) * vec2(0.5, 0.5);\n" + "}"; + +static const char* const _fragmentShader = + "varying vec2 texCoord;\n" + "uniform sampler2D tex;\n" + + "void main() {\n" + " vec4 color = texture2D(tex, texCoord);\n" + " color.a = 1.;\n" + " gl_FragColor = color;\n" + "}"; + +static const GLfloat _vertices[] = { + -1.f, -1.f, + -1.f, 1.f, + 1.f, 1.f, + 1.f, -1.f, +}; + void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) { renderer->d.init = GBAVideoGLRendererInit; renderer->d.reset = GBAVideoGLRendererReset; @@ -40,20 +69,67 @@ void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) { renderer->d.disableBG[2] = false; renderer->d.disableBG[3] = false; renderer->d.disableOBJ = false; - - renderer->temporaryBuffer = 0; } void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { + struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + glGenFramebuffers(6, glRenderer->fbo); + glGenTextures(6, glRenderer->layers); + glGenTextures(1, &glRenderer->paletteTex); + + glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + GBAVideoGLRendererReset(renderer); } void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { - + struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + glDeleteFramebuffers(6, glRenderer->fbo); + glDeleteTextures(6, glRenderer->layers); + glDeleteTextures(1, &glRenderer->paletteTex); } void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) { + struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[5]); + glBindTexture(GL_TEXTURE_2D, glRenderer->layers[5]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[5], 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glRenderer->compositeProgram = glCreateProgram(); + GLuint vs = glCreateShader(GL_VERTEX_SHADER); + GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); + + const GLchar* shaderBuffer[2]; + const GLubyte* version = glGetString(GL_VERSION); + shaderBuffer[0] = _gl3Header; + shaderBuffer[1] = _vertexShader; + glShaderSource(vs, 2, shaderBuffer, 0); + shaderBuffer[1] = _fragmentShader; + glShaderSource(fs, 2, shaderBuffer, 0); + + glAttachShader(glRenderer->compositeProgram, vs); + glAttachShader(glRenderer->compositeProgram, fs); + char log[1024]; + + glCompileShader(fs); + glGetShaderInfoLog(fs, 1024, 0, log); + + glCompileShader(vs); + glGetShaderInfoLog(vs, 1024, 0, log); + + glLinkProgram(glRenderer->compositeProgram); + glGetProgramInfoLog(glRenderer->compositeProgram, 1024, 0, log); + + glRenderer->paletteDirty = false; } void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) { @@ -65,7 +141,8 @@ void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) } void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) { - + struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + glRenderer->paletteDirty = true; } uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) { @@ -73,11 +150,33 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, } void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { + struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + if (glRenderer->paletteDirty) { + glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 256, 2, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, glRenderer->d.palette); + glRenderer->paletteDirty = false; + } + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[5]); + glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); + glUseProgram(glRenderer->compositeProgram); + glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex); + glUniform1i(0, 0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, _vertices); + glEnableVertexAttribArray(0); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glBindFramebuffer(GL_FRAMEBUFFER, 0); } void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) { - + struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + glFinish(); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[5]); + glPixelStorei(GL_PACK_ROW_LENGTH, glRenderer->outputBufferStride); + glReadPixels(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, GL_RGBA, GL_UNSIGNED_BYTE, glRenderer->outputBuffer); + glClearColor(1.f, 1.f, 0.f, 1.f); + glClear(GL_COLOR_BUFFER_BIT); + glBindFramebuffer(GL_FRAMEBUFFER, 0); } void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) { From e99cd34b668d0b0449dd8e2062cc7dad918f6aeb Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 9 May 2019 13:32:51 -0700 Subject: [PATCH 05/44] GBA Video: Move video registers and structs into common file --- .../internal/gba/renderers/video-software.h | 23 +---------------- include/mgba/internal/gba/video.h | 25 +++++++++++++++++-- src/gba/renderers/video-software.c | 2 +- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/include/mgba/internal/gba/renderers/video-software.h b/include/mgba/internal/gba/renderers/video-software.h index 8bfc3da9b..3012cc10f 100644 --- a/include/mgba/internal/gba/renderers/video-software.h +++ b/include/mgba/internal/gba/renderers/video-software.h @@ -49,13 +49,6 @@ struct GBAVideoSoftwareBackground { int32_t offsetY; }; -enum BlendEffect { - BLEND_NONE = 0, - BLEND_ALPHA = 1, - BLEND_BRIGHTEN = 2, - BLEND_DARKEN = 3 -}; - enum { #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 @@ -87,20 +80,6 @@ struct WindowRegion { uint8_t start; }; -DECL_BITFIELD(GBAWindowControl, uint8_t); -DECL_BIT(GBAWindowControl, Bg0Enable, 0); -DECL_BIT(GBAWindowControl, Bg1Enable, 1); -DECL_BIT(GBAWindowControl, Bg2Enable, 2); -DECL_BIT(GBAWindowControl, Bg3Enable, 3); -DECL_BIT(GBAWindowControl, ObjEnable, 4); -DECL_BIT(GBAWindowControl, BlendEnable, 5); - -DECL_BITFIELD(GBAMosaicControl, uint16_t); -DECL_BITS(GBAMosaicControl, BgH, 0, 4); -DECL_BITS(GBAMosaicControl, BgV, 4, 4); -DECL_BITS(GBAMosaicControl, ObjH, 8, 4); -DECL_BITS(GBAMosaicControl, ObjV, 12, 4); - struct WindowControl { GBAWindowControl packed; int8_t priority; @@ -133,7 +112,7 @@ struct GBAVideoSoftwareRenderer { unsigned target2Obj; unsigned target2Bd; bool blendDirty; - enum BlendEffect blendEffect; + enum GBAVideoBlendEffect blendEffect; color_t normalPalette[512]; color_t variantPalette[512]; diff --git a/include/mgba/internal/gba/video.h b/include/mgba/internal/gba/video.h index 15e3a4381..699d2f238 100644 --- a/include/mgba/internal/gba/video.h +++ b/include/mgba/internal/gba/video.h @@ -32,18 +32,25 @@ enum { BASE_TILE = 0x00010000 }; -enum ObjMode { +enum GBAVideoObjMode { OBJ_MODE_NORMAL = 0, OBJ_MODE_SEMITRANSPARENT = 1, OBJ_MODE_OBJWIN = 2 }; -enum ObjShape { +enum GBAVideoObjShape { OBJ_SHAPE_SQUARE = 0, OBJ_SHAPE_HORIZONTAL = 1, OBJ_SHAPE_VERTICAL = 2 }; +enum GBAVideoBlendEffect { + BLEND_NONE = 0, + BLEND_ALPHA = 1, + BLEND_BRIGHTEN = 2, + BLEND_DARKEN = 3 +}; + DECL_BITFIELD(GBAObjAttributesA, uint16_t); DECL_BITS(GBAObjAttributesA, Y, 0, 8); DECL_BIT(GBAObjAttributesA, Transformed, 8); @@ -144,6 +151,20 @@ DECL_BIT(GBARegisterBLDCNT, Target2Bg3, 11); DECL_BIT(GBARegisterBLDCNT, Target2Obj, 12); DECL_BIT(GBARegisterBLDCNT, Target2Bd, 13); +DECL_BITFIELD(GBAWindowControl, uint8_t); +DECL_BIT(GBAWindowControl, Bg0Enable, 0); +DECL_BIT(GBAWindowControl, Bg1Enable, 1); +DECL_BIT(GBAWindowControl, Bg2Enable, 2); +DECL_BIT(GBAWindowControl, Bg3Enable, 3); +DECL_BIT(GBAWindowControl, ObjEnable, 4); +DECL_BIT(GBAWindowControl, BlendEnable, 5); + +DECL_BITFIELD(GBAMosaicControl, uint16_t); +DECL_BITS(GBAMosaicControl, BgH, 0, 4); +DECL_BITS(GBAMosaicControl, BgV, 4, 4); +DECL_BITS(GBAMosaicControl, ObjH, 8, 4); +DECL_BITS(GBAMosaicControl, ObjV, 12, 4); + struct GBAVideoRenderer { void (*init)(struct GBAVideoRenderer* renderer); void (*reset)(struct GBAVideoRenderer* renderer); diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c index 951febc5e..46f6cb958 100644 --- a/src/gba/renderers/video-software.c +++ b/src/gba/renderers/video-software.c @@ -787,7 +787,7 @@ static void GBAVideoSoftwareRendererWriteBGY_HI(struct GBAVideoSoftwareBackgroun } static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer, uint16_t value) { - enum BlendEffect oldEffect = renderer->blendEffect; + enum GBAVideoBlendEffect oldEffect = renderer->blendEffect; renderer->bg[0].target1 = GBARegisterBLDCNTGetTarget1Bg0(value); renderer->bg[1].target1 = GBARegisterBLDCNTGetTarget1Bg1(value); From bb997f9b461019cb9a75449987817e97295ef1ae Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 9 May 2019 15:15:16 -0700 Subject: [PATCH 06/44] GBA Video: Start mode 0 GL renderer --- include/mgba/internal/gba/renderers/gl.h | 103 ++++++ src/gba/renderers/gl.c | 411 +++++++++++++++++++++-- 2 files changed, 482 insertions(+), 32 deletions(-) create mode 100644 include/mgba/internal/gba/renderers/gl.h diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h new file mode 100644 index 000000000..d7ea02c6f --- /dev/null +++ b/include/mgba/internal/gba/renderers/gl.h @@ -0,0 +1,103 @@ +/* Copyright (c) 2013-2019 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 VIDEO_GL_H +#define VIDEO_GL_H + +#include + +CXX_GUARD_START + +#include +#include +#include +#include + +#ifdef USE_EPOXY +#include +#elif defined(BUILD_GL) +#ifdef __APPLE__ +#include +#else +#define GL_GLEXT_PROTOTYPES +#include +#include +#endif +#else +#include +#endif + +struct GBAVideoGLBackground { + GLuint fbo; + GLuint tex; + GLuint program; + + unsigned index; + int enabled; + unsigned priority; + uint32_t charBase; + int mosaic; + int multipalette; + uint32_t screenBase; + int overflow; + int size; + int target1; + int target2; + uint16_t x; + uint16_t y; + int32_t refx; + int32_t refy; + int16_t dx; + int16_t dmx; + int16_t dy; + int16_t dmy; + int32_t sx; + int32_t sy; +}; + +struct GBAVideoGLRenderer { + struct GBAVideoRenderer d; + + struct GBAVideoGLBackground bg[4]; + + GLuint fbo[2]; + GLuint layers[2]; + + color_t* outputBuffer; + int outputBufferStride; + + GLuint paletteTex; + bool paletteDirty; + + GLuint oamTex; + bool oamDirty; + + GLuint vramTex; + unsigned vramDirty; + + GLuint bgPrograms[6]; + GLuint objProgram; + + GLuint compositeProgram; + + GBARegisterDISPCNT dispcnt; + + unsigned target1Obj; + unsigned target1Bd; + unsigned target2Obj; + unsigned target2Bd; + enum GBAVideoBlendEffect blendEffect; + uint16_t blda; + uint16_t bldb; + uint16_t bldy; + + GBAMosaicControl mosaic; +}; + +void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer); + +CXX_GUARD_END + +#endif \ No newline at end of file diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 4a7fab348..b87701d8c 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -22,33 +22,73 @@ static void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer); static void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels); static void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels); +static void GBAVideoGLRendererUpdateDISPCNT(struct GBAVideoGLRenderer* renderer); +static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16_t value); +static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value); +static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value); +static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value); +static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value); +static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value); + static const GLchar* const _gl3Header = - "#version 120\n"; + "#version 130\n"; static const char* const _vertexShader = - "attribute vec4 position;\n" + "attribute vec2 position;\n" + "uniform int y;\n" + "const ivec2 maxPos = ivec2(240, 160);\n" "varying vec2 texCoord;\n" "void main() {\n" - " gl_Position = position;\n" - " texCoord = (position.st + vec2(1.0, -1.0)) * vec2(0.5, 0.5);\n" + " vec2 local = (position + vec2(0, y)) / vec2(1., maxPos.y);\n" + " gl_Position = vec4(local * 2. - 1., 0., 1.);\n" + " texCoord = local * maxPos;\n" "}"; -static const char* const _fragmentShader = +static const char* const _renderTile16 = + "vec4 renderTile(int tile, int tileBase, int paletteId, ivec2 localCoord) {\n" + " int address = tileBase + tile * 16 + (localCoord.x >> 2) + (localCoord.y << 1);\n" + " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n" + " int entry = int(halfrow[3 - (localCoord.x & 3)] * 16.);\n" + " vec4 color = texelFetch(palette, ivec2(entry, paletteId), 0);\n" + " if (entry > 0) {\n" + " color.a = 1.;\n" + " } else {\n" + " color.a = 0.;\n" + " }\n" + " return color;\n" + "}"; + +static const char* const _renderMode0 = "varying vec2 texCoord;\n" - "uniform sampler2D tex;\n" + "uniform sampler2D vram;\n" + "uniform sampler2D palette;\n" + "uniform int screenBase;\n" + "uniform int charBase;\n" + "uniform ivec2 offset;\n" + + "vec4 renderTile(int tile, int tileBase, int paletteId, ivec2 localCoord);\n" "void main() {\n" - " vec4 color = texture2D(tex, texCoord);\n" - " color.a = 1.;\n" - " gl_FragColor = color;\n" + " ivec2 coord = ivec2(texCoord) + offset;\n" + " int mapAddress = screenBase + (coord.x >> 3) + (coord.y >> 3) * 32;\n" + " vec4 map = texelFetch(vram, ivec2(mapAddress & 255, mapAddress >> 8), 0);\n" + " int flags = int(map.g * 15.9);\n" + " if ((flags & 4) == 4) {\n" + " coord.x ^= 7;\n" + " }\n" + " if ((flags & 8) == 8) {\n" + " coord.y ^= 7;\n" + " }\n" + " int tile = int(map.a * 15.9) + int(map.b * 15.9) * 16 + (flags & 0x3) * 256;\n" + " gl_FragColor = renderTile(tile, charBase, int(map.r * 15.9), coord & 7);\n" "}"; -static const GLfloat _vertices[] = { - -1.f, -1.f, - -1.f, 1.f, - 1.f, 1.f, - 1.f, -1.f, +static const GLint _vertices[] = { + 0, 0, + 0, 1, + 1, 1, + 1, 0, }; void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) { @@ -73,8 +113,8 @@ void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) { void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; - glGenFramebuffers(6, glRenderer->fbo); - glGenTextures(6, glRenderer->layers); + glGenFramebuffers(2, glRenderer->fbo); + glGenTextures(2, glRenderer->layers); glGenTextures(1, &glRenderer->paletteTex); @@ -82,39 +122,48 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glGenTextures(1, &glRenderer->vramTex); + + glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + GBAVideoGLRendererReset(renderer); } void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; - glDeleteFramebuffers(6, glRenderer->fbo); - glDeleteTextures(6, glRenderer->layers); + glDeleteFramebuffers(2, glRenderer->fbo); + glDeleteTextures(2, glRenderer->layers); glDeleteTextures(1, &glRenderer->paletteTex); + glDeleteTextures(1, &glRenderer->vramTex); + glDeleteTextures(1, &glRenderer->oamTex); } void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[5]); - glBindTexture(GL_TEXTURE_2D, glRenderer->layers[5]); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); + glBindTexture(GL_TEXTURE_2D, glRenderer->layers[1]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[5], 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[1], 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); glRenderer->compositeProgram = glCreateProgram(); GLuint vs = glCreateShader(GL_VERTEX_SHADER); GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); - const GLchar* shaderBuffer[2]; + const GLchar* shaderBuffer[3]; const GLubyte* version = glGetString(GL_VERSION); shaderBuffer[0] = _gl3Header; shaderBuffer[1] = _vertexShader; glShaderSource(vs, 2, shaderBuffer, 0); - shaderBuffer[1] = _fragmentShader; - glShaderSource(fs, 2, shaderBuffer, 0); + shaderBuffer[1] = _renderMode0; + shaderBuffer[2] = _renderTile16; + glShaderSource(fs, 3, shaderBuffer, 0); glAttachShader(glRenderer->compositeProgram, vs); glAttachShader(glRenderer->compositeProgram, fs); @@ -122,46 +171,294 @@ void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) { glCompileShader(fs); glGetShaderInfoLog(fs, 1024, 0, log); + if (log[0]) { + mLOG(GBA_VIDEO, ERROR, "Fragment shader compilation failure: %s", log); + } glCompileShader(vs); glGetShaderInfoLog(vs, 1024, 0, log); + if (log[0]) { + mLOG(GBA_VIDEO, ERROR, "Vertex shader compilation failure: %s", log); + } glLinkProgram(glRenderer->compositeProgram); glGetProgramInfoLog(glRenderer->compositeProgram, 1024, 0, log); + if (log[0]) { + mLOG(GBA_VIDEO, ERROR, "Program link failure: %s", log); + } - glRenderer->paletteDirty = false; + glRenderer->paletteDirty = true; + glRenderer->vramDirty = 0xFFFFFF; + + glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 256, 192, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0); } void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) { - + struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + glRenderer->vramDirty |= 1 << (address >> 12); } void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) { - + UNUSED(oam); + struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + glRenderer->oamDirty = true; } void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) { + UNUSED(address); + UNUSED(value); struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; glRenderer->paletteDirty = true; } uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) { + struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + if (renderer->cache) { + GBAVideoCacheWriteVideoRegister(renderer->cache, address, value); + } + switch (address) { + case REG_DISPCNT: + value &= 0xFFF7; + glRenderer->dispcnt = value; + //GBAVideoGLRendererUpdateDISPCNT(glRenderer); + break; + case REG_BG0CNT: + value &= 0xDFFF; + GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[0], value); + //GBAVideoGLRendererUpdateDISPCNT(glRenderer); + break; + case REG_BG1CNT: + value &= 0xDFFF; + GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[1], value); + //GBAVideoGLRendererUpdateDISPCNT(glRenderer); + break; + case REG_BG2CNT: + value &= 0xFFFF; + GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[2], value); + //GBAVideoGLRendererUpdateDISPCNT(glRenderer); + break; + case REG_BG3CNT: + value &= 0xFFFF; + GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[3], value); + //GBAVideoGLRendererUpdateDISPCNT(glRenderer); + break; + case REG_BG0HOFS: + value &= 0x01FF; + glRenderer->bg[0].x = value; + break; + case REG_BG0VOFS: + value &= 0x01FF; + glRenderer->bg[0].y = value; + break; + case REG_BG1HOFS: + value &= 0x01FF; + glRenderer->bg[1].x = value; + break; + case REG_BG1VOFS: + value &= 0x01FF; + glRenderer->bg[1].y = value; + break; + case REG_BG2HOFS: + value &= 0x01FF; + glRenderer->bg[2].x = value; + break; + case REG_BG2VOFS: + value &= 0x01FF; + glRenderer->bg[2].y = value; + break; + case REG_BG3HOFS: + value &= 0x01FF; + glRenderer->bg[3].x = value; + break; + case REG_BG3VOFS: + value &= 0x01FF; + glRenderer->bg[3].y = value; + break; + case REG_BG2PA: + glRenderer->bg[2].dx = value; + break; + case REG_BG2PB: + glRenderer->bg[2].dmx = value; + break; + case REG_BG2PC: + glRenderer->bg[2].dy = value; + break; + case REG_BG2PD: + glRenderer->bg[2].dmy = value; + break; + case REG_BG2X_LO: + GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[2], value); + break; + case REG_BG2X_HI: + GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[2], value); + break; + case REG_BG2Y_LO: + GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[2], value); + break; + case REG_BG2Y_HI: + GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[2], value); + break; + case REG_BG3PA: + glRenderer->bg[3].dx = value; + break; + case REG_BG3PB: + glRenderer->bg[3].dmx = value; + break; + case REG_BG3PC: + glRenderer->bg[3].dy = value; + break; + case REG_BG3PD: + glRenderer->bg[3].dmy = value; + break; + case REG_BG3X_LO: + GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[3], value); + break; + case REG_BG3X_HI: + GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[3], value); + break; + case REG_BG3Y_LO: + GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[3], value); + break; + case REG_BG3Y_HI: + GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[3], value); + break; + case REG_BLDCNT: + GBAVideoGLRendererWriteBLDCNT(glRenderer, value); + value &= 0x3FFF; + break; + case REG_BLDALPHA: + glRenderer->blda = value & 0x1F; + if (glRenderer->blda > 0x10) { + glRenderer->blda = 0x10; + } + glRenderer->bldb = (value >> 8) & 0x1F; + if (glRenderer->bldb > 0x10) { + glRenderer->bldb = 0x10; + } + value &= 0x1F1F; + break; + case REG_BLDY: + value &= 0x1F; + if (value > 0x10) { + value = 0x10; + } + if (glRenderer->bldy != value) { + glRenderer->bldy = value; + } + break; + case REG_WIN0H: + /*glRenderer->winN[0].h.end = value; + glRenderer->winN[0].h.start = value >> 8; + if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[0].h.start > glRenderer->winN[0].h.end) { + glRenderer->winN[0].h.start = 0; + } + if (glRenderer->winN[0].h.end > GBA_VIDEO_HORIZONTAL_PIXELS) { + glRenderer->winN[0].h.end = GBA_VIDEO_HORIZONTAL_PIXELS; + if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) { + glRenderer->winN[0].h.start = GBA_VIDEO_HORIZONTAL_PIXELS; + } + }*/ + break; + case REG_WIN1H: + /*glRenderer->winN[1].h.end = value; + glRenderer->winN[1].h.start = value >> 8; + if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[1].h.start > glRenderer->winN[1].h.end) { + glRenderer->winN[1].h.start = 0; + } + if (glRenderer->winN[1].h.end > GBA_VIDEO_HORIZONTAL_PIXELS) { + glRenderer->winN[1].h.end = GBA_VIDEO_HORIZONTAL_PIXELS; + if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) { + glRenderer->winN[1].h.start = GBA_VIDEO_HORIZONTAL_PIXELS; + } + }*/ + break; + case REG_WIN0V: + /*glRenderer->winN[0].v.end = value; + glRenderer->winN[0].v.start = value >> 8; + if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[0].v.start > glRenderer->winN[0].v.end) { + glRenderer->winN[0].v.start = 0; + } + if (glRenderer->winN[0].v.end > GBA_VIDEO_VERTICAL_PIXELS) { + glRenderer->winN[0].v.end = GBA_VIDEO_VERTICAL_PIXELS; + if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS) { + glRenderer->winN[0].v.start = GBA_VIDEO_VERTICAL_PIXELS; + } + }*/ + break; + case REG_WIN1V: + /*glRenderer->winN[1].v.end = value; + glRenderer->winN[1].v.start = value >> 8; + if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[1].v.start > glRenderer->winN[1].v.end) { + glRenderer->winN[1].v.start = 0; + } + if (glRenderer->winN[1].v.end > GBA_VIDEO_VERTICAL_PIXELS) { + glRenderer->winN[1].v.end = GBA_VIDEO_VERTICAL_PIXELS; + if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS) { + glRenderer->winN[1].v.start = GBA_VIDEO_VERTICAL_PIXELS; + } + }*/ + break; + case REG_WININ: + value &= 0x3F3F; + //glRenderer->winN[0].control.packed = value; + //glRenderer->winN[1].control.packed = value >> 8; + break; + case REG_WINOUT: + value &= 0x3F3F; + //glRenderer->winout.packed = value; + //glRenderer->objwin.packed = value >> 8; + break; + case REG_MOSAIC: + glRenderer->mosaic = value; + break; + case REG_GREENSWP: + mLOG(GBA_VIDEO, STUB, "Stub video register write: 0x%03X", address); + break; + default: + mLOG(GBA_VIDEO, GAME_ERROR, "Invalid video register: 0x%03X", address); + } + return value; } void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; if (glRenderer->paletteDirty) { glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 256, 2, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, glRenderer->d.palette); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 16, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, glRenderer->d.palette); glRenderer->paletteDirty = false; } - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[5]); + if (glRenderer->oamDirty) { + glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 4, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, glRenderer->d.oam); + glRenderer->oamDirty = false; + } + int i; + for (i = 0; i < 24; ++i) { + if (!(glRenderer->vramDirty & (1 << i))) { + continue; + } + // TODO: PBOs + glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 8 * i, 256, 8, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, &glRenderer->d.vram[2048 * i]); + } + glRenderer->vramDirty = 0; + + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); glUseProgram(glRenderer->compositeProgram); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex); + glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex); - glUniform1i(0, 0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, _vertices); + glUniform1i(0, y); + glUniform1i(1, 0); + glUniform1i(2, 1); + glUniform1i(3, glRenderer->bg[0].screenBase); + glUniform1i(4, glRenderer->bg[0].charBase); + glUniform2i(5, glRenderer->bg[0].x, glRenderer->bg[0].y); + glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -171,7 +468,7 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; glFinish(); - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[5]); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); glPixelStorei(GL_PACK_ROW_LENGTH, glRenderer->outputBufferStride); glReadPixels(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, GL_RGBA, GL_UNSIGNED_BYTE, glRenderer->outputBuffer); glClearColor(1.f, 1.f, 0.f, 1.f); @@ -187,3 +484,53 @@ void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t strid } +static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16_t value) { + bg->priority = GBARegisterBGCNTGetPriority(value); + bg->charBase = GBARegisterBGCNTGetCharBase(value) << 13; + bg->mosaic = GBARegisterBGCNTGetMosaic(value); + bg->multipalette = GBARegisterBGCNTGet256Color(value); + bg->screenBase = GBARegisterBGCNTGetScreenBase(value) << 10; + bg->overflow = GBARegisterBGCNTGetOverflow(value); + bg->size = GBARegisterBGCNTGetSize(value); +} + +static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value) { + bg->refx = (bg->refx & 0xFFFF0000) | value; + bg->sx = bg->refx; +} + +static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value) { + bg->refx = (bg->refx & 0x0000FFFF) | (value << 16); + bg->refx <<= 4; + bg->refx >>= 4; + bg->sx = bg->refx; +} + +static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value) { + bg->refy = (bg->refy & 0xFFFF0000) | value; + bg->sy = bg->refy; +} + +static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value) { + bg->refy = (bg->refy & 0x0000FFFF) | (value << 16); + bg->refy <<= 4; + bg->refy >>= 4; + bg->sy = bg->refy; +} + +static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value) { + renderer->bg[0].target1 = GBARegisterBLDCNTGetTarget1Bg0(value); + renderer->bg[1].target1 = GBARegisterBLDCNTGetTarget1Bg1(value); + renderer->bg[2].target1 = GBARegisterBLDCNTGetTarget1Bg2(value); + renderer->bg[3].target1 = GBARegisterBLDCNTGetTarget1Bg3(value); + renderer->bg[0].target2 = GBARegisterBLDCNTGetTarget2Bg0(value); + renderer->bg[1].target2 = GBARegisterBLDCNTGetTarget2Bg1(value); + renderer->bg[2].target2 = GBARegisterBLDCNTGetTarget2Bg2(value); + renderer->bg[3].target2 = GBARegisterBLDCNTGetTarget2Bg3(value); + + renderer->blendEffect = GBARegisterBLDCNTGetEffect(value); + renderer->target1Obj = GBARegisterBLDCNTGetTarget1Obj(value); + renderer->target1Bd = GBARegisterBLDCNTGetTarget1Bd(value); + renderer->target2Obj = GBARegisterBLDCNTGetTarget2Obj(value); + renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value); +} \ No newline at end of file From b86857696a32a0c28fc542d6fda7071836b4cd39 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 10 May 2019 00:32:48 -0700 Subject: [PATCH 07/44] GBA Video: Mostly functional mode 0 GL renderer --- include/mgba/internal/gba/renderers/gl.h | 5 +- src/gba/renderers/gl.c | 330 +++++++++++++++++------ 2 files changed, 252 insertions(+), 83 deletions(-) diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index d7ea02c6f..254ba743d 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -32,7 +32,6 @@ CXX_GUARD_START struct GBAVideoGLBackground { GLuint fbo; GLuint tex; - GLuint program; unsigned index; int enabled; @@ -63,7 +62,7 @@ struct GBAVideoGLRenderer { struct GBAVideoGLBackground bg[4]; GLuint fbo[2]; - GLuint layers[2]; + GLuint layers[4]; color_t* outputBuffer; int outputBufferStride; @@ -77,7 +76,7 @@ struct GBAVideoGLRenderer { GLuint vramTex; unsigned vramDirty; - GLuint bgPrograms[6]; + GLuint bgProgram[6]; GLuint objProgram; GLuint compositeProgram; diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index b87701d8c..7ae958a0e 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -30,17 +30,25 @@ static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint1 static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value); static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value); +static void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); +static void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); +static void GBAVideoGLRendererDrawBackgroundMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); +static void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); +static void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); + +#define TEST_LAYER_ENABLED(X) !renderer->disableBG[X] && glRenderer->bg[X].enabled == 4 && glRenderer->bg[X].priority == priority + static const GLchar* const _gl3Header = "#version 130\n"; static const char* const _vertexShader = "attribute vec2 position;\n" - "uniform int y;\n" + "uniform ivec2 loc;\n" "const ivec2 maxPos = ivec2(240, 160);\n" "varying vec2 texCoord;\n" "void main() {\n" - " vec2 local = (position + vec2(0, y)) / vec2(1., maxPos.y);\n" + " vec2 local = (position + vec2(0, loc.y)) / vec2(1., maxPos.y);\n" " gl_Position = vec4(local * 2. - 1., 0., 1.);\n" " texCoord = local * maxPos;\n" "}"; @@ -49,9 +57,24 @@ static const char* const _renderTile16 = "vec4 renderTile(int tile, int tileBase, int paletteId, ivec2 localCoord) {\n" " int address = tileBase + tile * 16 + (localCoord.x >> 2) + (localCoord.y << 1);\n" " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n" - " int entry = int(halfrow[3 - (localCoord.x & 3)] * 16.);\n" + " int entry = int(halfrow[3 - (localCoord.x & 3)] * 15.9);\n" " vec4 color = texelFetch(palette, ivec2(entry, paletteId), 0);\n" - " if (entry > 0) {\n" + " if (entry == 0) {\n" + " color.a = 0;\n" + " } else {\n" + " color.a = 1;\n" + " }\n" + " return color;\n" + "}"; + +static const char* const _renderTile256 = + "vec4 renderTile(int tile, int tileBase, int paletteId, ivec2 localCoord) {\n" + " int address = tileBase + tile * 32 + (localCoord.x >> 1) + (localCoord.y << 2);\n" + " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n" + " int entry = int(halfrow[3 - 2 * (localCoord.x & 1)] * 15.9);\n" + " int pal2 = int(halfrow[2 - 2 * (localCoord.x & 1)] * 15.9);\n" + " vec4 color = texelFetch(palette, ivec2(entry, pal2 + (paletteId & 16)), 0);\n" + " if (pal2 > 0 || entry > 0) {\n" " color.a = 1.;\n" " } else {\n" " color.a = 0.;\n" @@ -70,7 +93,7 @@ static const char* const _renderMode0 = "vec4 renderTile(int tile, int tileBase, int paletteId, ivec2 localCoord);\n" "void main() {\n" - " ivec2 coord = ivec2(texCoord) + offset;\n" + " ivec2 coord = (ivec2(texCoord) + offset) & 255;\n" " int mapAddress = screenBase + (coord.x >> 3) + (coord.y >> 3) * 32;\n" " vec4 map = texelFetch(vram, ivec2(mapAddress & 255, mapAddress >> 8), 0);\n" " int flags = int(map.g * 15.9);\n" @@ -84,6 +107,18 @@ static const char* const _renderMode0 = " gl_FragColor = renderTile(tile, charBase, int(map.r * 15.9), coord & 7);\n" "}"; +static const char* const _composite = + "varying vec2 texCoord;\n" + "uniform sampler2D layer;\n" + + "void main() {\n" + " vec4 color = texelFetch(layer, ivec2(texCoord), 0);\n" + " if (color.a == 0) {\n" + " discard;\n" + " }\n" + " gl_FragColor = color;\n" + "}"; + static const GLint _vertices[] = { 0, 0, 0, 1, @@ -111,22 +146,114 @@ void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) { renderer->d.disableOBJ = false; } +void _compileBackground(struct GBAVideoGLRenderer* glRenderer, GLuint program, const char** shaderBuffer, int shaderBufferLines, GLuint vs, char* log) { + GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); + glAttachShader(program, vs); + glAttachShader(program, fs); + glShaderSource(fs, shaderBufferLines, shaderBuffer, 0); + glCompileShader(fs); + glGetShaderInfoLog(fs, 1024, 0, log); + if (log[0]) { + mLOG(GBA_VIDEO, ERROR, "Fragment shader compilation failure: %s", log); + } + glLinkProgram(program); + glGetProgramInfoLog(program, 1024, 0, log); + if (log[0]) { + mLOG(GBA_VIDEO, ERROR, "Program link failure: %s", log); + } + glDeleteShader(fs); +} + void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; glGenFramebuffers(2, glRenderer->fbo); - glGenTextures(2, glRenderer->layers); + glGenTextures(4, glRenderer->layers); glGenTextures(1, &glRenderer->paletteTex); - glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glGenTextures(1, &glRenderer->vramTex); - glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 256, 192, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0); + + glGenTextures(1, &glRenderer->oamTex); + glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); + glBindTexture(GL_TEXTURE_2D, glRenderer->layers[2]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[2], 0); + + glBindTexture(GL_TEXTURE_2D, glRenderer->layers[3]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, glRenderer->layers[3], 0); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + int i; + for (i = 0; i < 4; ++i) { + glRenderer->bg[i].index = i; + glGenFramebuffers(1, &glRenderer->bg[i].fbo); + glGenTextures(1, &glRenderer->bg[i].tex); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo); + glBindTexture(GL_TEXTURE_2D, glRenderer->bg[i].tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->bg[i].tex, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + glRenderer->compositeProgram = glCreateProgram(); + glRenderer->objProgram = glCreateProgram(); + glRenderer->bgProgram[0] = glCreateProgram(); + glRenderer->bgProgram[1] = glCreateProgram(); + glRenderer->bgProgram[2] = glCreateProgram(); + glRenderer->bgProgram[3] = glCreateProgram(); + glRenderer->bgProgram[4] = glCreateProgram(); + glRenderer->bgProgram[5] = glCreateProgram(); + + char log[1024]; + const GLchar* shaderBuffer[8]; + shaderBuffer[0] = _gl3Header; + + GLuint vs = glCreateShader(GL_VERTEX_SHADER); + shaderBuffer[1] = _vertexShader; + glShaderSource(vs, 2, shaderBuffer, 0); + glCompileShader(vs); + glGetShaderInfoLog(vs, 1024, 0, log); + if (log[0]) { + mLOG(GBA_VIDEO, ERROR, "Vertex shader compilation failure: %s", log); + } + + shaderBuffer[1] = _renderMode0; + + shaderBuffer[2] = _renderTile16; + _compileBackground(glRenderer, glRenderer->bgProgram[0], shaderBuffer, 3, vs, log); + + shaderBuffer[2] = _renderTile256; + _compileBackground(glRenderer, glRenderer->bgProgram[1], shaderBuffer, 3, vs, log); + + shaderBuffer[1] = _composite; + _compileBackground(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log); + + glDeleteShader(vs); GBAVideoGLRendererReset(renderer); } @@ -134,7 +261,7 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; glDeleteFramebuffers(2, glRenderer->fbo); - glDeleteTextures(2, glRenderer->layers); + glDeleteTextures(4, glRenderer->layers); glDeleteTextures(1, &glRenderer->paletteTex); glDeleteTextures(1, &glRenderer->vramTex); glDeleteTextures(1, &glRenderer->oamTex); @@ -142,56 +269,9 @@ void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); - glBindTexture(GL_TEXTURE_2D, glRenderer->layers[1]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[1], 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - glRenderer->compositeProgram = glCreateProgram(); - GLuint vs = glCreateShader(GL_VERTEX_SHADER); - GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); - - const GLchar* shaderBuffer[3]; - const GLubyte* version = glGetString(GL_VERSION); - shaderBuffer[0] = _gl3Header; - shaderBuffer[1] = _vertexShader; - glShaderSource(vs, 2, shaderBuffer, 0); - shaderBuffer[1] = _renderMode0; - shaderBuffer[2] = _renderTile16; - glShaderSource(fs, 3, shaderBuffer, 0); - - glAttachShader(glRenderer->compositeProgram, vs); - glAttachShader(glRenderer->compositeProgram, fs); - char log[1024]; - - glCompileShader(fs); - glGetShaderInfoLog(fs, 1024, 0, log); - if (log[0]) { - mLOG(GBA_VIDEO, ERROR, "Fragment shader compilation failure: %s", log); - } - - glCompileShader(vs); - glGetShaderInfoLog(vs, 1024, 0, log); - if (log[0]) { - mLOG(GBA_VIDEO, ERROR, "Vertex shader compilation failure: %s", log); - } - - glLinkProgram(glRenderer->compositeProgram); - glGetProgramInfoLog(glRenderer->compositeProgram, 1024, 0, log); - if (log[0]) { - mLOG(GBA_VIDEO, ERROR, "Program link failure: %s", log); - } glRenderer->paletteDirty = true; glRenderer->vramDirty = 0xFFFFFF; - - glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 256, 192, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0); } void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) { @@ -222,27 +302,23 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, case REG_DISPCNT: value &= 0xFFF7; glRenderer->dispcnt = value; - //GBAVideoGLRendererUpdateDISPCNT(glRenderer); + GBAVideoGLRendererUpdateDISPCNT(glRenderer); break; case REG_BG0CNT: value &= 0xDFFF; GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[0], value); - //GBAVideoGLRendererUpdateDISPCNT(glRenderer); break; case REG_BG1CNT: value &= 0xDFFF; GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[1], value); - //GBAVideoGLRendererUpdateDISPCNT(glRenderer); break; case REG_BG2CNT: value &= 0xFFFF; GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[2], value); - //GBAVideoGLRendererUpdateDISPCNT(glRenderer); break; case REG_BG3CNT: value &= 0xFFFF; GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[3], value); - //GBAVideoGLRendererUpdateDISPCNT(glRenderer); break; case REG_BG0HOFS: value &= 0x01FF; @@ -445,24 +521,51 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } glRenderer->vramDirty = 0; - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); - glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); - glUseProgram(glRenderer->compositeProgram); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex); - glActiveTexture(GL_TEXTURE0 + 1); - glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex); - glUniform1i(0, y); - glUniform1i(1, 0); - glUniform1i(2, 1); - glUniform1i(3, glRenderer->bg[0].screenBase); - glUniform1i(4, glRenderer->bg[0].charBase); - glUniform2i(5, glRenderer->bg[0].x, glRenderer->bg[0].y); - glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); - glEnableVertexAttribArray(0); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + unsigned priority; + for (priority = 0; priority < 4; ++priority) { + if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) { + GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[0], y); + } + if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) { + GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[1], y); + } + if (TEST_LAYER_ENABLED(2)) { + switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) { + case 0: + GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[2], y); + break; + case 1: + case 2: + //GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[2], y); + break; + case 3: + //GBAVideoGLRendererDrawBackgroundMode3(glRenderer, &glRenderer->bg[2], y); + break; + case 4: + //GBAVideoGLRendererDrawBackgroundMode4(glRenderer, &glRenderer->bg[2], y); + break; + case 5: + //GBAVideoGLRendererDrawBackgroundMode5(glRenderer, &glRenderer->bg[2], y); + break; + } + } + if (TEST_LAYER_ENABLED(3)) { + switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) { + case 0: + GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[3], y); + break; + case 2: + //GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[3], y); + break; + } + } + } + if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) { + glRenderer->bg[2].sx += glRenderer->bg[2].dmx; + glRenderer->bg[2].sy += glRenderer->bg[2].dmy; + glRenderer->bg[3].sx += glRenderer->bg[3].dmx; + glRenderer->bg[3].sy += glRenderer->bg[3].dmy; + } } void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) { @@ -471,7 +574,15 @@ void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) { glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); glPixelStorei(GL_PACK_ROW_LENGTH, glRenderer->outputBufferStride); glReadPixels(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, GL_RGBA, GL_UNSIGNED_BYTE, glRenderer->outputBuffer); - glClearColor(1.f, 1.f, 0.f, 1.f); + glClearColor(1.f, 1.f, 1.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[0].fbo); + glClear(GL_COLOR_BUFFER_BIT); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[1].fbo); + glClear(GL_COLOR_BUFFER_BIT); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[2].fbo); + glClear(GL_COLOR_BUFFER_BIT); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[3].fbo); glClear(GL_COLOR_BUFFER_BIT); glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -484,6 +595,28 @@ void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t strid } +static void _enableBg(struct GBAVideoGLRenderer* renderer, int bg, bool active) { + int wasActive = renderer->bg[bg].enabled; + if (!active) { + renderer->bg[bg].enabled = 0; + } else if (!wasActive && active) { + /*if (renderer->nextY == 0 || GBARegisterDISPCNTGetMode(renderer->dispcnt) > 2) { + // TODO: Investigate in more depth how switching background works in different modes + renderer->bg[bg].enabled = 4; + } else { + renderer->bg[bg].enabled = 1; + }*/ + renderer->bg[bg].enabled = 4; + } +} + +static void GBAVideoGLRendererUpdateDISPCNT(struct GBAVideoGLRenderer* renderer) { + _enableBg(renderer, 0, GBARegisterDISPCNTGetBg0Enable(renderer->dispcnt)); + _enableBg(renderer, 1, GBARegisterDISPCNTGetBg1Enable(renderer->dispcnt)); + _enableBg(renderer, 2, GBARegisterDISPCNTGetBg2Enable(renderer->dispcnt)); + _enableBg(renderer, 3, GBARegisterDISPCNTGetBg3Enable(renderer->dispcnt)); +} + static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16_t value) { bg->priority = GBARegisterBGCNTGetPriority(value); bg->charBase = GBARegisterBGCNTGetCharBase(value) << 13; @@ -533,4 +666,41 @@ static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, u renderer->target1Bd = GBARegisterBLDCNTGetTarget1Bd(value); renderer->target2Obj = GBARegisterBLDCNTGetTarget2Obj(value); renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value); +} + +void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { + glBindFramebuffer(GL_FRAMEBUFFER, background->fbo); + glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); + glScissor(0, 1, GBA_VIDEO_HORIZONTAL_PIXELS, 1); + glUseProgram(renderer->bgProgram[background->multipalette ? 1 : 0]); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, renderer->vramTex); + glActiveTexture(GL_TEXTURE0 + 1); + glBindTexture(GL_TEXTURE_2D, renderer->paletteTex); + glUniform2i(0, 0, y); + glUniform1i(1, 0); + glUniform1i(2, 1); + glUniform1i(3, background->screenBase); + glUniform1i(4, background->charBase); + glUniform2i(5, background->x, background->y); + glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); + glEnableVertexAttribArray(0); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[1]); + glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); + glScissor(0, 1, GBA_VIDEO_HORIZONTAL_PIXELS, 1); + glDepthFunc(GL_LESS); + glEnable(GL_DEPTH_TEST); + glUseProgram(renderer->compositeProgram); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, background->tex); + glUniform2i(0, (background->priority << 3) + (background->index << 1) + 1, y); + glUniform1i(1, 0); + glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); + glEnableVertexAttribArray(0); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDisable(GL_DEPTH_TEST); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); } \ No newline at end of file From 1a04532d4b00a33fa6adef638290a2f9632badfb Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 10 May 2019 11:10:21 -0700 Subject: [PATCH 08/44] GBA Video: Finish GL mode 0 renderer --- src/gba/renderers/gl.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 7ae958a0e..ac026dc68 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -88,12 +88,17 @@ static const char* const _renderMode0 = "uniform sampler2D palette;\n" "uniform int screenBase;\n" "uniform int charBase;\n" + "uniform int size;\n" "uniform ivec2 offset;\n" "vec4 renderTile(int tile, int tileBase, int paletteId, ivec2 localCoord);\n" "void main() {\n" - " ivec2 coord = (ivec2(texCoord) + offset) & 255;\n" + " ivec2 coord = ivec2(texCoord) + offset;\n" + " if ((size & 1) == 1) {\n" + " coord.y += coord.x & 256;\n" + " }\n" + " coord.x &= 255;\n" " int mapAddress = screenBase + (coord.x >> 3) + (coord.y >> 3) * 32;\n" " vec4 map = texelFetch(vram, ivec2(mapAddress & 255, mapAddress >> 8), 0);\n" " int flags = int(map.g * 15.9);\n" @@ -521,6 +526,14 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } glRenderer->vramDirty = 0; + uint32_t backdrop = M_RGB5_TO_RGB8(renderer->palette[0]); + glClearColor(((backdrop >> 16) & 0xFF) / 256., ((backdrop >> 8) & 0xFF) / 256., (backdrop & 0xFF) / 256., 0.f); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); + glEnable(GL_SCISSOR_TEST); + glScissor(0, y, GBA_VIDEO_HORIZONTAL_PIXELS, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + unsigned priority; for (priority = 0; priority < 4; ++priority) { if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) { @@ -574,16 +587,6 @@ void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) { glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); glPixelStorei(GL_PACK_ROW_LENGTH, glRenderer->outputBufferStride); glReadPixels(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, GL_RGBA, GL_UNSIGNED_BYTE, glRenderer->outputBuffer); - glClearColor(1.f, 1.f, 1.f, 0.f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[0].fbo); - glClear(GL_COLOR_BUFFER_BIT); - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[1].fbo); - glClear(GL_COLOR_BUFFER_BIT); - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[2].fbo); - glClear(GL_COLOR_BUFFER_BIT); - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[3].fbo); - glClear(GL_COLOR_BUFFER_BIT); glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -669,9 +672,16 @@ static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, u } void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { + int inY = y + background->y; + int yBase = inY & 0xFF; + if (background->size == 2) { + yBase += inY & 0x100; + } else if (background->size == 3) { + yBase += (inY & 0x100) << 1; + } glBindFramebuffer(GL_FRAMEBUFFER, background->fbo); glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); - glScissor(0, 1, GBA_VIDEO_HORIZONTAL_PIXELS, 1); + glScissor(0, y, GBA_VIDEO_HORIZONTAL_PIXELS, 1); glUseProgram(renderer->bgProgram[background->multipalette ? 1 : 0]); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, renderer->vramTex); @@ -682,14 +692,15 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, glUniform1i(2, 1); glUniform1i(3, background->screenBase); glUniform1i(4, background->charBase); - glUniform2i(5, background->x, background->y); + glUniform1i(5, background->size); + glUniform2i(6, background->x, yBase - y); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[1]); glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); - glScissor(0, 1, GBA_VIDEO_HORIZONTAL_PIXELS, 1); + glScissor(0, y, GBA_VIDEO_HORIZONTAL_PIXELS, 1); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); glUseProgram(renderer->compositeProgram); From 51a174e4c57ca7a8189ee53b6bc227fe5698442a Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 10 May 2019 12:17:19 -0700 Subject: [PATCH 09/44] GBA Video: Better batching/depth testing --- src/gba/renderers/gl.c | 49 ++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index ac026dc68..73e7bb78a 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -43,14 +43,14 @@ static const GLchar* const _gl3Header = static const char* const _vertexShader = "attribute vec2 position;\n" - "uniform ivec2 loc;\n" - "const ivec2 maxPos = ivec2(240, 160);\n" + "uniform ivec3 loc;\n" + "const ivec3 maxPos = ivec3(240, 160, 32);\n" "varying vec2 texCoord;\n" "void main() {\n" - " vec2 local = (position + vec2(0, loc.y)) / vec2(1., maxPos.y);\n" - " gl_Position = vec4(local * 2. - 1., 0., 1.);\n" - " texCoord = local * maxPos;\n" + " vec2 local = (position * loc.x + vec2(0, loc.y)) / vec2(1., maxPos.y);\n" + " gl_Position = vec4(local * 2. - 1., loc.z / float(maxPos.z), 1.);\n" + " texCoord = local * maxPos.xy;\n" "}"; static const char* const _renderTile16 = @@ -531,7 +531,12 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); glEnable(GL_SCISSOR_TEST); glScissor(0, y, GBA_VIDEO_HORIZONTAL_PIXELS, 1); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); + if (y == 0) { + glClearDepthf(1); + glClear(GL_DEPTH_BUFFER_BIT); + } glBindFramebuffer(GL_FRAMEBUFFER, 0); unsigned priority; @@ -687,7 +692,7 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, glBindTexture(GL_TEXTURE_2D, renderer->vramTex); glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, renderer->paletteTex); - glUniform2i(0, 0, y); + glUniform3i(0, 1, y, 0); glUniform1i(1, 0); glUniform1i(2, 1); glUniform1i(3, background->screenBase); @@ -698,20 +703,22 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[1]); - glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); - glScissor(0, y, GBA_VIDEO_HORIZONTAL_PIXELS, 1); - glDepthFunc(GL_LESS); - glEnable(GL_DEPTH_TEST); - glUseProgram(renderer->compositeProgram); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, background->tex); - glUniform2i(0, (background->priority << 3) + (background->index << 1) + 1, y); - glUniform1i(1, 0); - glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); - glEnableVertexAttribArray(0); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisable(GL_DEPTH_TEST); + if ((y & 0x1F) == 0x1F) { + glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[1]); + glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); + glScissor(0, y & ~0x1F, GBA_VIDEO_HORIZONTAL_PIXELS, 0x20); + glDepthFunc(GL_LESS); + glEnable(GL_DEPTH_TEST); + glUseProgram(renderer->compositeProgram); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, background->tex); + glUniform3i(0, 0x20, y & ~0x1F, (background->priority << 3) + (background->index << 1) + 1); + glUniform1i(1, 0); + glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); + glEnableVertexAttribArray(0); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDisable(GL_DEPTH_TEST); + } glBindFramebuffer(GL_FRAMEBUFFER, 0); } \ No newline at end of file From 7edf7cdb159618bfe4c58d1306f004238556b25a Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 10 May 2019 12:26:39 -0700 Subject: [PATCH 10/44] GBA Video: Pass disabled layers through proxy --- src/gba/extra/proxy.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gba/extra/proxy.c b/src/gba/extra/proxy.c index ea884db3b..38bfb4514 100644 --- a/src/gba/extra/proxy.c +++ b/src/gba/extra/proxy.c @@ -182,6 +182,11 @@ static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerD } break; case DIRTY_SCANLINE: + proxyRenderer->backend->disableBG[0] = proxyRenderer->d.disableBG[0]; + proxyRenderer->backend->disableBG[1] = proxyRenderer->d.disableBG[1]; + proxyRenderer->backend->disableBG[2] = proxyRenderer->d.disableBG[2]; + proxyRenderer->backend->disableBG[3] = proxyRenderer->d.disableBG[3]; + proxyRenderer->backend->disableOBJ = proxyRenderer->d.disableOBJ; if (item->address < GBA_VIDEO_VERTICAL_PIXELS) { proxyRenderer->backend->drawScanline(proxyRenderer->backend, item->address); } From 3e0675f539218973801f40d1abcacc2ffbf89e6c Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 10 May 2019 14:56:27 -0700 Subject: [PATCH 11/44] GBA Video: Add GL mode 2 --- include/mgba/internal/gba/renderers/gl.h | 2 + src/gba/renderers/gl.c | 161 ++++++++++++++++++----- 2 files changed, 131 insertions(+), 32 deletions(-) diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index 254ba743d..402b81afe 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -93,6 +93,8 @@ struct GBAVideoGLRenderer { uint16_t bldy; GBAMosaicControl mosaic; + + int scale; }; void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer); diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 73e7bb78a..36e2602f8 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -54,8 +54,8 @@ static const char* const _vertexShader = "}"; static const char* const _renderTile16 = - "vec4 renderTile(int tile, int tileBase, int paletteId, ivec2 localCoord) {\n" - " int address = tileBase + tile * 16 + (localCoord.x >> 2) + (localCoord.y << 1);\n" + "vec4 renderTile(int tile, int paletteId, ivec2 localCoord) {\n" + " int address = charBase + tile * 16 + (localCoord.x >> 2) + (localCoord.y << 1);\n" " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n" " int entry = int(halfrow[3 - (localCoord.x & 3)] * 15.9);\n" " vec4 color = texelFetch(palette, ivec2(entry, paletteId), 0);\n" @@ -68,8 +68,8 @@ static const char* const _renderTile16 = "}"; static const char* const _renderTile256 = - "vec4 renderTile(int tile, int tileBase, int paletteId, ivec2 localCoord) {\n" - " int address = tileBase + tile * 32 + (localCoord.x >> 1) + (localCoord.y << 2);\n" + "vec4 renderTile(int tile, int paletteId, ivec2 localCoord) {\n" + " int address = charBase + tile * 32 + (localCoord.x >> 1) + (localCoord.y << 2);\n" " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n" " int entry = int(halfrow[3 - 2 * (localCoord.x & 1)] * 15.9);\n" " int pal2 = int(halfrow[2 - 2 * (localCoord.x & 1)] * 15.9);\n" @@ -91,7 +91,7 @@ static const char* const _renderMode0 = "uniform int size;\n" "uniform ivec2 offset;\n" - "vec4 renderTile(int tile, int tileBase, int paletteId, ivec2 localCoord);\n" + "vec4 renderTile(int tile, int paletteId, ivec2 localCoord);\n" "void main() {\n" " ivec2 coord = ivec2(texCoord) + offset;\n" @@ -109,15 +109,70 @@ static const char* const _renderMode0 = " coord.y ^= 7;\n" " }\n" " int tile = int(map.a * 15.9) + int(map.b * 15.9) * 16 + (flags & 0x3) * 256;\n" - " gl_FragColor = renderTile(tile, charBase, int(map.r * 15.9), coord & 7);\n" + " gl_FragColor = renderTile(tile, int(map.r * 15.9), coord & 7);\n" + "}"; + +static const char* const _fetchTileOverflow = + "vec4 fetchTile(ivec2 coord) {\n" + " int sizeAdjusted = (0x8000 << size) - 1;\n" + " coord &= sizeAdjusted;\n" + " return renderTile(coord);\n" + "}"; + +static const char* const _fetchTileNoOverflow = + "vec4 fetchTile(ivec2 coord) {\n" + " int sizeAdjusted = (0x8000 << size) - 1;\n" + " ivec2 outerCoord = coord & ~sizeAdjusted;\n" + " if ((outerCoord.x | outerCoord.y) != 0) {\n" + " vec4 color = texelFetch(palette, ivec2(0, 0), 0);\n" + " color.a = 0;\n" + " return color;\n" + " }\n" + " return renderTile(coord);\n" + "}"; + +static const char* const _renderMode2 = + "varying vec2 texCoord;\n" + "uniform sampler2D vram;\n" + "uniform sampler2D palette;\n" + "uniform int screenBase;\n" + "uniform int charBase;\n" + "uniform int size;\n" + "uniform ivec2 offset;\n" + "uniform mat2x2 transform;\n" + + "vec4 fetchTile(ivec2 coord);\n" + + "vec4 renderTile(ivec2 coord) {\n" + " int map = (coord.x >> 11) + (((coord.y >> 7) & 0x7F0) << size);\n" + " int mapAddress = screenBase + (map >> 1);\n" + " vec4 twomaps = texelFetch(vram, ivec2(mapAddress & 255, mapAddress >> 8), 0);\n" + " int tile = int(twomaps[3 - 2 * (map & 1)] * 15.9) + int(twomaps[2 - 2 * (map & 1)] * 15.9) * 16;\n" + " int address = charBase + tile * 32 + ((coord.x >> 9) & 3) + ((coord.y >> 6) & 0x1C);\n" + " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n" + " int entry = int(halfrow[3 - ((coord.x >> 7) & 2)] * 15.9);\n" + " int pal2 = int(halfrow[2 - ((coord.x >> 7) & 2)] * 15.9);\n" + " vec4 color = texelFetch(palette, ivec2(entry, pal2), 0);\n" + " if (pal2 > 0 || entry > 0) {\n" + " color.a = 1.;\n" + " } else {\n" + " color.a = 0.;\n" + " }\n" + " return color;\n" + "}" + + "void main() {\n" + " ivec2 coord = ivec2(transform[0] * texCoord.x) + ivec2(transform[1] * fract(texCoord.y)) + offset;\n" + " gl_FragColor = fetchTile(coord);\n" "}"; static const char* const _composite = "varying vec2 texCoord;\n" "uniform sampler2D layer;\n" + "uniform int scale;\n" "void main() {\n" - " vec4 color = texelFetch(layer, ivec2(texCoord), 0);\n" + " vec4 color = texelFetch(layer, ivec2(texCoord * scale), 0);\n" " if (color.a == 0) {\n" " discard;\n" " }\n" @@ -149,6 +204,8 @@ void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) { renderer->d.disableBG[2] = false; renderer->d.disableBG[3] = false; renderer->d.disableOBJ = false; + + renderer->scale = 1; } void _compileBackground(struct GBAVideoGLRenderer* glRenderer, GLuint program, const char** shaderBuffer, int shaderBufferLines, GLuint vs, char* log) { @@ -196,7 +253,7 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[2], 0); glBindTexture(GL_TEXTURE_2D, glRenderer->layers[3]); @@ -204,7 +261,7 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, glRenderer->layers[3], 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -220,7 +277,7 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->bg[i].tex, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -255,6 +312,14 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { shaderBuffer[2] = _renderTile256; _compileBackground(glRenderer, glRenderer->bgProgram[1], shaderBuffer, 3, vs, log); + shaderBuffer[1] = _renderMode2; + + shaderBuffer[2] = _fetchTileOverflow; + _compileBackground(glRenderer, glRenderer->bgProgram[2], shaderBuffer, 3, vs, log); + + shaderBuffer[2] = _fetchTileNoOverflow; + _compileBackground(glRenderer, glRenderer->bgProgram[3], shaderBuffer, 3, vs, log); + shaderBuffer[1] = _composite; _compileBackground(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log); @@ -530,7 +595,7 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { glClearColor(((backdrop >> 16) & 0xFF) / 256., ((backdrop >> 8) & 0xFF) / 256., (backdrop & 0xFF) / 256., 0.f); glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); glEnable(GL_SCISSOR_TEST); - glScissor(0, y, GBA_VIDEO_HORIZONTAL_PIXELS, 1); + glScissor(0, y * glRenderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, glRenderer->scale); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); if (y == 0) { @@ -554,7 +619,7 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { break; case 1: case 2: - //GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[2], y); + GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[2], y); break; case 3: //GBAVideoGLRendererDrawBackgroundMode3(glRenderer, &glRenderer->bg[2], y); @@ -573,7 +638,7 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[3], y); break; case 2: - //GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[3], y); + GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[3], y); break; } } @@ -591,7 +656,7 @@ void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) { glFinish(); glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); glPixelStorei(GL_PACK_ROW_LENGTH, glRenderer->outputBufferStride); - glReadPixels(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, GL_RGBA, GL_UNSIGNED_BYTE, glRenderer->outputBuffer); + glReadPixels(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, GL_RGBA, GL_UNSIGNED_BYTE, glRenderer->outputBuffer); glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -676,6 +741,27 @@ static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, u renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value); } +static void _compositeLayer(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { + if ((y & 0x1F) != 0x1F) { + return; + } + glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[1]); + glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); + glScissor(0, (y * renderer->scale) % (0x20 * renderer->scale), GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale); + glDepthFunc(GL_LESS); + glEnable(GL_DEPTH_TEST); + glUseProgram(renderer->compositeProgram); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, background->tex); + glUniform3i(0, 0x20, y & ~0x1F, (background->priority << 3) + (background->index << 1) + 1); + glUniform1i(1, 0); + glUniform1i(2, renderer->scale); + glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); + glEnableVertexAttribArray(0); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDisable(GL_DEPTH_TEST); +} + void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { int inY = y + background->y; int yBase = inY & 0xFF; @@ -685,8 +771,8 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, yBase += (inY & 0x100) << 1; } glBindFramebuffer(GL_FRAMEBUFFER, background->fbo); - glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); - glScissor(0, y, GBA_VIDEO_HORIZONTAL_PIXELS, 1); + glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); + glScissor(0, y * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale); glUseProgram(renderer->bgProgram[background->multipalette ? 1 : 0]); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, renderer->vramTex); @@ -703,22 +789,33 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - if ((y & 0x1F) == 0x1F) { - glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[1]); - glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); - glScissor(0, y & ~0x1F, GBA_VIDEO_HORIZONTAL_PIXELS, 0x20); - glDepthFunc(GL_LESS); - glEnable(GL_DEPTH_TEST); - glUseProgram(renderer->compositeProgram); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, background->tex); - glUniform3i(0, 0x20, y & ~0x1F, (background->priority << 3) + (background->index << 1) + 1); - glUniform1i(1, 0); - glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); - glEnableVertexAttribArray(0); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisable(GL_DEPTH_TEST); - } + _compositeLayer(renderer, background, y); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { + glBindFramebuffer(GL_FRAMEBUFFER, background->fbo); + glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); + glScissor(0, y * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale); + glUseProgram(renderer->bgProgram[background->overflow ? 2 : 3]); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, renderer->vramTex); + glActiveTexture(GL_TEXTURE0 + 1); + glBindTexture(GL_TEXTURE_2D, renderer->paletteTex); + glUniform3i(0, 1, y, 0); + glUniform1i(1, 0); + glUniform1i(2, 1); + glUniform1i(3, background->screenBase); + glUniform1i(4, background->charBase); + glUniform1i(5, background->size); + glUniform2i(6, background->sx, background->sy); + glUniformMatrix2fv(7, 1, GL_FALSE, (GLfloat[]) { background->dx, background->dy, background->dmx, background->dmy }); + glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); + glEnableVertexAttribArray(0); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + _compositeLayer(renderer, background, y); glBindFramebuffer(GL_FRAMEBUFFER, 0); } \ No newline at end of file From 36477ca40d66b72a401ae7d7a6fdcf4dc056d840 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 10 May 2019 15:04:14 -0700 Subject: [PATCH 12/44] Core: Begin on video scale hack --- src/gba/core.c | 14 +++++++++++--- src/platform/qt/CoreController.cpp | 2 +- src/platform/qt/DisplayGL.cpp | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/gba/core.c b/src/gba/core.c index 0edd73b85..3feb64176 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -255,12 +255,19 @@ static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* con mCoreConfigCopyValue(&core->config, config, "threadedVideo"); #endif mCoreConfigCopyValue(&core->config, config, "hwaccelVideo"); + mCoreConfigCopyValue(&core->config, config, "videoScale"); } static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) { - UNUSED(core); - *width = GBA_VIDEO_HORIZONTAL_PIXELS; - *height = GBA_VIDEO_VERTICAL_PIXELS; + struct GBACore* gbacore = (struct GBACore*) core; + int fakeBool; + int scale = 1; + if (mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) { + scale = gbacore->glRenderer.scale; + } + + *width = GBA_VIDEO_HORIZONTAL_PIXELS * scale; + *height = GBA_VIDEO_VERTICAL_PIXELS * scale; } static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) { @@ -406,6 +413,7 @@ static void _GBACoreReset(struct mCore* core) { #endif if (mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) { renderer = &gbacore->glRenderer.d; + mCoreConfigGetIntValue(&core->config, "videoScale", &gbacore->glRenderer.scale); } if (core->videoLogger) { gbacore->proxyRenderer.logger = core->videoLogger; diff --git a/src/platform/qt/CoreController.cpp b/src/platform/qt/CoreController.cpp index 5f6f8ba04..37ea45cac 100644 --- a/src/platform/qt/CoreController.cpp +++ b/src/platform/qt/CoreController.cpp @@ -40,7 +40,7 @@ CoreController::CoreController(mCore* core, QObject* parent) m_threadContext.core = core; m_threadContext.userData = this; - QSize size(256, 512); + QSize size(1024, 2048); m_buffers[0].resize(size.width() * size.height() * sizeof(color_t)); m_buffers[1].resize(size.width() * size.height() * sizeof(color_t)); m_buffers[0].fill(0xFF); diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index 722359255..8ff657016 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -251,7 +251,7 @@ PainterGL::PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent) m_backend->lockAspectRatio = false; for (int i = 0; i < 2; ++i) { - m_free.append(new uint32_t[256 * 256]); + m_free.append(new uint32_t[1024 * 2048]); } } From fab3091ed1eb9c74c51add1a35b4129e3d6587b4 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 10 May 2019 15:33:54 -0700 Subject: [PATCH 13/44] Core: Some texid plumbing --- include/mgba/core/core.h | 1 + include/mgba/internal/gba/renderers/gl.h | 5 ++--- src/gb/core.c | 6 ++++++ src/gba/core.c | 27 ++++++++++++++++-------- src/gba/renderers/gl.c | 20 +++++++----------- 5 files changed, 35 insertions(+), 24 deletions(-) diff --git a/include/mgba/core/core.h b/include/mgba/core/core.h index fe08ae0cd..124b02411 100644 --- a/include/mgba/core/core.h +++ b/include/mgba/core/core.h @@ -70,6 +70,7 @@ struct mCore { void (*desiredVideoDimensions)(struct mCore*, unsigned* width, unsigned* height); void (*setVideoBuffer)(struct mCore*, color_t* buffer, size_t stride); + void (*setVideoGLTex)(struct mCore*, unsigned texid); void (*getPixels)(struct mCore*, const void** buffer, size_t* stride); void (*putPixels)(struct mCore*, const void* buffer, size_t stride); diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index 402b81afe..4467bee9c 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -62,10 +62,9 @@ struct GBAVideoGLRenderer { struct GBAVideoGLBackground bg[4]; GLuint fbo[2]; - GLuint layers[4]; + GLuint layers[3]; - color_t* outputBuffer; - int outputBufferStride; + GLuint outputTex; GLuint paletteTex; bool paletteDirty; diff --git a/src/gb/core.c b/src/gb/core.c index 99f11029d..20e383393 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -233,6 +233,11 @@ static void _GBCoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t st gbcore->renderer.outputBufferStride = stride; } +static void _GBCoreSetVideoGLTex(struct mCore* core, unsigned texid) { + UNUSED(core); + UNUSED(texid); +} + static void _GBCoreGetPixels(struct mCore* core, const void** buffer, size_t* stride) { struct GBCore* gbcore = (struct GBCore*) core; gbcore->renderer.d.getPixels(&gbcore->renderer.d, stride, buffer); @@ -887,6 +892,7 @@ struct mCore* GBCoreCreate(void) { core->loadConfig = _GBCoreLoadConfig; core->desiredVideoDimensions = _GBCoreDesiredVideoDimensions; core->setVideoBuffer = _GBCoreSetVideoBuffer; + core->setVideoGLTex = _GBCoreSetVideoGLTex; core->getPixels = _GBCoreGetPixels; core->putPixels = _GBCorePutPixels; core->getAudioChannel = _GBCoreGetAudioChannel; diff --git a/src/gba/core.c b/src/gba/core.c index 3feb64176..2c6207d8b 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -168,9 +168,11 @@ static bool _GBACoreInit(struct mCore* core) { gba->rtcSource = &core->rtc.d; GBAVideoSoftwareRendererCreate(&gbacore->renderer); - GBAVideoGLRendererCreate(&gbacore->glRenderer); gbacore->renderer.outputBuffer = NULL; + GBAVideoGLRendererCreate(&gbacore->glRenderer); + gbacore->glRenderer.outputTex = -1; + #ifndef DISABLE_THREADING mVideoThreadProxyCreate(&gbacore->threadProxy); #endif @@ -274,11 +276,14 @@ static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t s struct GBACore* gbacore = (struct GBACore*) core; gbacore->renderer.outputBuffer = buffer; gbacore->renderer.outputBufferStride = stride; - gbacore->glRenderer.outputBuffer = buffer; - gbacore->glRenderer.outputBufferStride = stride; memset(gbacore->renderer.scanlineDirty, 0xFFFFFFFF, sizeof(gbacore->renderer.scanlineDirty)); } +static void _GBACoreSetVideoGLTex(struct mCore* core, unsigned texid) { + struct GBACore* gbacore = (struct GBACore*) core; + gbacore->glRenderer.outputTex = texid; +} + static void _GBACoreGetPixels(struct mCore* core, const void** buffer, size_t* stride) { struct GBACore* gbacore = (struct GBACore*) core; gbacore->renderer.d.getPixels(&gbacore->renderer.d, stride, buffer); @@ -401,9 +406,16 @@ static void _GBACoreChecksum(const struct mCore* core, void* data, enum mCoreChe static void _GBACoreReset(struct mCore* core) { struct GBACore* gbacore = (struct GBACore*) core; struct GBA* gba = (struct GBA*) core->board; - if (gbacore->renderer.outputBuffer) { - struct GBAVideoRenderer* renderer = &gbacore->renderer.d; + if (gbacore->renderer.outputBuffer || gbacore->glRenderer.outputTex != (unsigned) -1) { + struct GBAVideoRenderer* renderer; + if (gbacore->renderer.outputBuffer) { + renderer = &gbacore->renderer.d; + } int fakeBool; + if (gbacore->glRenderer.outputTex != (unsigned) -1 && mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) { + renderer = &gbacore->glRenderer.d; + mCoreConfigGetIntValue(&core->config, "videoScale", &gbacore->glRenderer.scale); + } #ifndef DISABLE_THREADING if (mCoreConfigGetIntValue(&core->config, "threadedVideo", &fakeBool) && fakeBool) { if (!core->videoLogger) { @@ -411,10 +423,6 @@ static void _GBACoreReset(struct mCore* core) { } } #endif - if (mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) { - renderer = &gbacore->glRenderer.d; - mCoreConfigGetIntValue(&core->config, "videoScale", &gbacore->glRenderer.scale); - } if (core->videoLogger) { gbacore->proxyRenderer.logger = core->videoLogger; GBAVideoProxyRendererCreate(&gbacore->proxyRenderer, renderer); @@ -951,6 +959,7 @@ struct mCore* GBACoreCreate(void) { core->loadConfig = _GBACoreLoadConfig; core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions; core->setVideoBuffer = _GBACoreSetVideoBuffer; + core->setVideoGLTex = _GBACoreSetVideoGLTex; core->getPixels = _GBACoreGetPixels; core->putPixels = _GBACorePutPixels; core->getAudioChannel = _GBACoreGetAudioChannel; diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 36e2602f8..e662a2779 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -229,7 +229,7 @@ void _compileBackground(struct GBAVideoGLRenderer* glRenderer, GLuint program, c void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; glGenFramebuffers(2, glRenderer->fbo); - glGenTextures(4, glRenderer->layers); + glGenTextures(3, glRenderer->layers); glGenTextures(1, &glRenderer->paletteTex); glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex); @@ -248,21 +248,21 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); - glBindTexture(GL_TEXTURE_2D, glRenderer->layers[2]); + glBindTexture(GL_TEXTURE_2D, glRenderer->outputTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[2], 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->outputTex, 0); - glBindTexture(GL_TEXTURE_2D, glRenderer->layers[3]); + glBindTexture(GL_TEXTURE_2D, glRenderer->layers[2]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, glRenderer->layers[3], 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, glRenderer->layers[2], 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -331,7 +331,7 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; glDeleteFramebuffers(2, glRenderer->fbo); - glDeleteTextures(4, glRenderer->layers); + glDeleteTextures(3, glRenderer->layers); glDeleteTextures(1, &glRenderer->paletteTex); glDeleteTextures(1, &glRenderer->vramTex); glDeleteTextures(1, &glRenderer->oamTex); @@ -652,12 +652,8 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) { - struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; - glFinish(); - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); - glPixelStorei(GL_PACK_ROW_LENGTH, glRenderer->outputBufferStride); - glReadPixels(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, GL_RGBA, GL_UNSIGNED_BYTE, glRenderer->outputBuffer); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + UNUSED(renderer); + glFlush(); } void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) { From 18e6acaf727d5fd69d2c8866c897121c020c8ccf Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 10 May 2019 16:16:29 -0700 Subject: [PATCH 14/44] GBA Video: Basic interpolation for GL renderer --- include/mgba/internal/gba/renderers/gl.h | 7 +++++++ src/gba/renderers/gl.c | 25 +++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index 4467bee9c..a305bf9c6 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -54,6 +54,13 @@ struct GBAVideoGLBackground { int16_t dmy; int32_t sx; int32_t sy; + + int16_t lastDx; + int16_t lastDmx; + int16_t lastDy; + int16_t lastDmy; + int32_t lastSx; + int32_t lastSy; }; struct GBAVideoGLRenderer { diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index e662a2779..9f7c786f1 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -139,7 +139,9 @@ static const char* const _renderMode2 = "uniform int charBase;\n" "uniform int size;\n" "uniform ivec2 offset;\n" + "uniform ivec2 oldOffset;\n" "uniform mat2x2 transform;\n" + "uniform mat2x2 oldTransform;\n" "vec4 fetchTile(ivec2 coord);\n" @@ -162,8 +164,9 @@ static const char* const _renderMode2 = "}" "void main() {\n" - " ivec2 coord = ivec2(transform[0] * texCoord.x) + ivec2(transform[1] * fract(texCoord.y)) + offset;\n" - " gl_FragColor = fetchTile(coord);\n" + " vec2 newCoord = transform[0] * texCoord.x + offset;\n" + " vec2 oldCoord = oldTransform[0] * texCoord.x + oldOffset;\n" + " gl_FragColor = fetchTile(ivec2(newCoord * fract(texCoord.y) + oldCoord * (1. - fract(texCoord.y))));\n" "}"; static const char* const _composite = @@ -644,8 +647,22 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } } if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) { + glRenderer->bg[2].lastDx = glRenderer->bg[2].dx; + glRenderer->bg[2].lastDy = glRenderer->bg[2].dy; + glRenderer->bg[2].lastDmx = glRenderer->bg[2].dmx; + glRenderer->bg[2].lastDmy = glRenderer->bg[2].dmy; + glRenderer->bg[2].lastSx = glRenderer->bg[2].sx; + glRenderer->bg[2].lastSy = glRenderer->bg[2].sy; + glRenderer->bg[2].lastSx = glRenderer->bg[2].sx; + glRenderer->bg[2].lastSy = glRenderer->bg[2].sy; glRenderer->bg[2].sx += glRenderer->bg[2].dmx; glRenderer->bg[2].sy += glRenderer->bg[2].dmy; + glRenderer->bg[3].lastDx = glRenderer->bg[3].dx; + glRenderer->bg[3].lastDy = glRenderer->bg[3].dy; + glRenderer->bg[3].lastDmx = glRenderer->bg[3].dmx; + glRenderer->bg[3].lastDmy = glRenderer->bg[3].dmy; + glRenderer->bg[3].lastSx = glRenderer->bg[3].sx; + glRenderer->bg[3].lastSy = glRenderer->bg[3].sy; glRenderer->bg[3].sx += glRenderer->bg[3].dmx; glRenderer->bg[3].sy += glRenderer->bg[3].dmy; } @@ -806,7 +823,9 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, glUniform1i(4, background->charBase); glUniform1i(5, background->size); glUniform2i(6, background->sx, background->sy); - glUniformMatrix2fv(7, 1, GL_FALSE, (GLfloat[]) { background->dx, background->dy, background->dmx, background->dmy }); + glUniform2i(7, background->lastSx, background->lastSy); + glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { background->dx, background->dy, background->dmx, background->dmy }); + glUniformMatrix2fv(9, 1, GL_FALSE, (GLfloat[]) { background->lastDx, background->lastDy, background->lastDmx, background->lastDmy }); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); From 8a6ea929d2b905e51aa21ccf460e9fb2696da0ea Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 10 May 2019 23:44:04 -0700 Subject: [PATCH 15/44] GBA Video: GL cleanup, initial work on blending --- include/mgba/internal/gba/renderers/gl.h | 22 ++-- src/gba/renderers/gl.c | 146 ++++++++++++++--------- 2 files changed, 97 insertions(+), 71 deletions(-) diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index a305bf9c6..f6b253891 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -29,6 +29,15 @@ CXX_GUARD_START #include #endif +struct GBAVideoGLAffine { + int16_t dx; + int16_t dmx; + int16_t dy; + int16_t dmy; + int32_t sx; + int32_t sy; +}; + struct GBAVideoGLBackground { GLuint fbo; GLuint tex; @@ -48,19 +57,8 @@ struct GBAVideoGLBackground { uint16_t y; int32_t refx; int32_t refy; - int16_t dx; - int16_t dmx; - int16_t dy; - int16_t dmy; - int32_t sx; - int32_t sy; - int16_t lastDx; - int16_t lastDmx; - int16_t lastDy; - int16_t lastDmy; - int32_t lastSx; - int32_t lastSy; + struct GBAVideoGLAffine affine[2]; }; struct GBAVideoGLRenderer { diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 9f7c786f1..3aec279bc 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -43,13 +43,13 @@ static const GLchar* const _gl3Header = static const char* const _vertexShader = "attribute vec2 position;\n" - "uniform ivec3 loc;\n" - "const ivec3 maxPos = ivec3(240, 160, 32);\n" + "uniform ivec2 loc;\n" + "const ivec2 maxPos = ivec2(240, 160);\n" "varying vec2 texCoord;\n" "void main() {\n" " vec2 local = (position * loc.x + vec2(0, loc.y)) / vec2(1., maxPos.y);\n" - " gl_Position = vec4(local * 2. - 1., loc.z / float(maxPos.z), 1.);\n" + " gl_Position = vec4(local * 2. - 1., 0., 1.);\n" " texCoord = local * maxPos.xy;\n" "}"; @@ -142,6 +142,7 @@ static const char* const _renderMode2 = "uniform ivec2 oldOffset;\n" "uniform mat2x2 transform;\n" "uniform mat2x2 oldTransform;\n" + "uniform int firstD;\n" "vec4 fetchTile(ivec2 coord);\n" @@ -164,22 +165,43 @@ static const char* const _renderMode2 = "}" "void main() {\n" - " vec2 newCoord = transform[0] * texCoord.x + offset;\n" - " vec2 oldCoord = oldTransform[0] * texCoord.x + oldOffset;\n" - " gl_FragColor = fetchTile(ivec2(newCoord * fract(texCoord.y) + oldCoord * (1. - fract(texCoord.y))));\n" + " float y = fract(texCoord.y);\n" + " float lin = y / ceil(y);\n" + " vec2 mixedTransform = mix(oldTransform[0], transform[0], lin);\n" + " vec2 mixedOffset = mix(oldOffset, offset, lin);\n" + " gl_FragColor = fetchTile(ivec2(mixedTransform * texCoord.x + mixedOffset));\n" "}"; static const char* const _composite = "varying vec2 texCoord;\n" - "uniform sampler2D layer;\n" + "uniform ivec3 inflags;\n" "uniform int scale;\n" + "uniform vec3 blend;\n" + "uniform sampler2D layer;\n" + "uniform sampler2D oldLayer;\n" + "uniform sampler2D buffer;\n" + "out vec4 color;\n" + "out vec3 flags;\n" "void main() {\n" - " vec4 color = texelFetch(layer, ivec2(texCoord * scale), 0);\n" - " if (color.a == 0) {\n" + " vec4 pix = texelFetch(layer, ivec2(texCoord * scale), 0);\n" + " if (pix.a == 0) {\n" " discard;\n" " }\n" - " gl_FragColor = color;\n" + " ivec3 oldFlags = ivec3(texelFetch(buffer, ivec2(texCoord * scale), 0).xyz * vec3(32., 4., 1.));\n" + " ivec3 outflags = ivec3(0, 0, 0);\n" + " if (inflags.x < oldFlags.x) {\n" + " outflags = inflags;\n" + " if ((inflags.y & 1) == 1 && (oldFlags.y & 2) == 2) {\n" + " vec4 oldpix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" + " pix *= blend.x;\n" + " pix += oldpix * blend.y;\n" + " }\n" + " } else {\n" + " pix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" + " }\n" + " color = pix;\n" + " flags = outflags / vec3(32., 4., 1.);\n" "}"; static const GLint _vertices[] = { @@ -264,8 +286,8 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, glRenderer->layers[2], 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[2], 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -325,6 +347,8 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { shaderBuffer[1] = _composite; _compileBackground(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log); + glBindFragDataLocation(glRenderer->compositeProgram, 0, "color"); + glBindFragDataLocation(glRenderer->compositeProgram, 1, "flags"); glDeleteShader(vs); @@ -426,16 +450,16 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, glRenderer->bg[3].y = value; break; case REG_BG2PA: - glRenderer->bg[2].dx = value; + glRenderer->bg[2].affine[0].dx = value; break; case REG_BG2PB: - glRenderer->bg[2].dmx = value; + glRenderer->bg[2].affine[0].dmx = value; break; case REG_BG2PC: - glRenderer->bg[2].dy = value; + glRenderer->bg[2].affine[0].dy = value; break; case REG_BG2PD: - glRenderer->bg[2].dmy = value; + glRenderer->bg[2].affine[0].dmy = value; break; case REG_BG2X_LO: GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[2], value); @@ -450,16 +474,16 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[2], value); break; case REG_BG3PA: - glRenderer->bg[3].dx = value; + glRenderer->bg[3].affine[0].dx = value; break; case REG_BG3PB: - glRenderer->bg[3].dmx = value; + glRenderer->bg[3].affine[0].dmx = value; break; case REG_BG3PC: - glRenderer->bg[3].dy = value; + glRenderer->bg[3].affine[0].dy = value; break; case REG_BG3PD: - glRenderer->bg[3].dmy = value; + glRenderer->bg[3].affine[0].dmy = value; break; case REG_BG3X_LO: GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[3], value); @@ -602,13 +626,15 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); if (y == 0) { - glClearDepthf(1); - glClear(GL_DEPTH_BUFFER_BIT); + glDrawBuffer(GL_COLOR_ATTACHMENT1); + glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2)) / 4.f, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + glDrawBuffer(GL_COLOR_ATTACHMENT0); } glBindFramebuffer(GL_FRAMEBUFFER, 0); unsigned priority; - for (priority = 0; priority < 4; ++priority) { + for (priority = 4; priority--;) { if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) { GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[0], y); } @@ -646,25 +672,15 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } } } + if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) { - glRenderer->bg[2].lastDx = glRenderer->bg[2].dx; - glRenderer->bg[2].lastDy = glRenderer->bg[2].dy; - glRenderer->bg[2].lastDmx = glRenderer->bg[2].dmx; - glRenderer->bg[2].lastDmy = glRenderer->bg[2].dmy; - glRenderer->bg[2].lastSx = glRenderer->bg[2].sx; - glRenderer->bg[2].lastSy = glRenderer->bg[2].sy; - glRenderer->bg[2].lastSx = glRenderer->bg[2].sx; - glRenderer->bg[2].lastSy = glRenderer->bg[2].sy; - glRenderer->bg[2].sx += glRenderer->bg[2].dmx; - glRenderer->bg[2].sy += glRenderer->bg[2].dmy; - glRenderer->bg[3].lastDx = glRenderer->bg[3].dx; - glRenderer->bg[3].lastDy = glRenderer->bg[3].dy; - glRenderer->bg[3].lastDmx = glRenderer->bg[3].dmx; - glRenderer->bg[3].lastDmy = glRenderer->bg[3].dmy; - glRenderer->bg[3].lastSx = glRenderer->bg[3].sx; - glRenderer->bg[3].lastSy = glRenderer->bg[3].sy; - glRenderer->bg[3].sx += glRenderer->bg[3].dmx; - glRenderer->bg[3].sy += glRenderer->bg[3].dmy; + memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine)); + memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine)); + + glRenderer->bg[2].affine[0].sx += glRenderer->bg[2].affine[0].dmx; + glRenderer->bg[2].affine[0].sy += glRenderer->bg[2].affine[0].dmy; + glRenderer->bg[3].affine[0].sx += glRenderer->bg[3].affine[0].dmx; + glRenderer->bg[3].affine[0].sy += glRenderer->bg[3].affine[0].dmy; } } @@ -715,26 +731,26 @@ static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16 static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value) { bg->refx = (bg->refx & 0xFFFF0000) | value; - bg->sx = bg->refx; + bg->affine[0].sx = bg->refx; } static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value) { bg->refx = (bg->refx & 0x0000FFFF) | (value << 16); bg->refx <<= 4; bg->refx >>= 4; - bg->sx = bg->refx; + bg->affine[0].sx = bg->refx; } static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value) { bg->refy = (bg->refy & 0xFFFF0000) | value; - bg->sy = bg->refy; + bg->affine[0].sy = bg->refy; } static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value) { bg->refy = (bg->refy & 0x0000FFFF) | (value << 16); bg->refy <<= 4; bg->refy >>= 4; - bg->sy = bg->refy; + bg->affine[0].sy = bg->refy; } static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value) { @@ -754,25 +770,32 @@ static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, u renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value); } -static void _compositeLayer(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { +static void _compositeLayer(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y, int flags) { if ((y & 0x1F) != 0x1F) { return; } glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[1]); glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); glScissor(0, (y * renderer->scale) % (0x20 * renderer->scale), GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale); - glDepthFunc(GL_LESS); - glEnable(GL_DEPTH_TEST); glUseProgram(renderer->compositeProgram); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, background->tex); - glUniform3i(0, 0x20, y & ~0x1F, (background->priority << 3) + (background->index << 1) + 1); - glUniform1i(1, 0); + glActiveTexture(GL_TEXTURE0 + 1); + glBindTexture(GL_TEXTURE_2D, renderer->outputTex); + glActiveTexture(GL_TEXTURE0 + 2); + glBindTexture(GL_TEXTURE_2D, renderer->layers[2]); + glUniform2i(0, 0x20, y & ~0x1F); + glUniform3i(1, (background->priority << 3) + (background->index << 1) + 1, flags, renderer->blendEffect); glUniform1i(2, renderer->scale); + glUniform3f(3, renderer->blda / 16.f, renderer->bldb / 16.f, renderer->bldy / 16.f); + glUniform1i(4, 0); + glUniform1i(5, 1); + glUniform1i(6, 2); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); + glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisable(GL_DEPTH_TEST); + glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); } void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { @@ -791,7 +814,7 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, glBindTexture(GL_TEXTURE_2D, renderer->vramTex); glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, renderer->paletteTex); - glUniform3i(0, 1, y, 0); + glUniform2i(0, 1, y); glUniform1i(1, 0); glUniform1i(2, 1); glUniform1i(3, background->screenBase); @@ -802,7 +825,7 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - _compositeLayer(renderer, background, y); + _compositeLayer(renderer, background, y, background->target1 | (background->target2 * 2)); glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -816,21 +839,26 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, glBindTexture(GL_TEXTURE_2D, renderer->vramTex); glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, renderer->paletteTex); - glUniform3i(0, 1, y, 0); + glUniform2i(0, 1, y); glUniform1i(1, 0); glUniform1i(2, 1); glUniform1i(3, background->screenBase); glUniform1i(4, background->charBase); glUniform1i(5, background->size); - glUniform2i(6, background->sx, background->sy); - glUniform2i(7, background->lastSx, background->lastSy); - glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { background->dx, background->dy, background->dmx, background->dmy }); - glUniformMatrix2fv(9, 1, GL_FALSE, (GLfloat[]) { background->lastDx, background->lastDy, background->lastDmx, background->lastDmy }); + glUniform2i(6, background->affine[0].sx, background->affine[0].sy); + glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { background->affine[0].dx, background->affine[0].dy, background->affine[0].dmx, background->affine[0].dmy }); + if (renderer->scale > 1) { + glUniform2i(7, background->affine[1].sx, background->affine[1].sy); + glUniformMatrix2fv(9, 1, GL_FALSE, (GLfloat[]) { background->affine[1].dx, background->affine[1].dy, background->affine[1].dmx, background->affine[1].dmy }); + } else { + glUniform2i(7, background->affine[0].sx, background->affine[0].sy); + glUniformMatrix2fv(9, 1, GL_FALSE, (GLfloat[]) { background->affine[0].dx, background->affine[0].dy, background->affine[0].dmx, background->affine[0].dmy }); + } glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - _compositeLayer(renderer, background, y); + _compositeLayer(renderer, background, y, background->target1 | (background->target2 * 2)); glBindFramebuffer(GL_FRAMEBUFFER, 0); } \ No newline at end of file From 68f0176ee4fccfc8bb5bf0678b4c7122f1eff0f3 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 11 May 2019 15:50:50 -0700 Subject: [PATCH 16/44] GBA Video: Mode 2 cubic interpolation --- include/mgba/internal/gba/renderers/gl.h | 4 +- src/gba/renderers/gl.c | 86 +++++++++++++++++++----- 2 files changed, 72 insertions(+), 18 deletions(-) diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index f6b253891..8da5583e1 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -58,7 +58,7 @@ struct GBAVideoGLBackground { int32_t refx; int32_t refy; - struct GBAVideoGLAffine affine[2]; + struct GBAVideoGLAffine affine[4]; }; struct GBAVideoGLRenderer { @@ -98,6 +98,8 @@ struct GBAVideoGLRenderer { GBAMosaicControl mosaic; + int firstAffine; + int scale; }; diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 3aec279bc..7e10e9ab6 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -138,11 +138,10 @@ static const char* const _renderMode2 = "uniform int screenBase;\n" "uniform int charBase;\n" "uniform int size;\n" - "uniform ivec2 offset;\n" - "uniform ivec2 oldOffset;\n" - "uniform mat2x2 transform;\n" - "uniform mat2x2 oldTransform;\n" - "uniform int firstD;\n" + "uniform ivec2[4] offset;\n" + "uniform ivec2[4] transform;\n" + "precision highp float;\n" + "precision highp int;\n" "vec4 fetchTile(ivec2 coord);\n" @@ -162,13 +161,21 @@ static const char* const _renderMode2 = " color.a = 0.;\n" " }\n" " return color;\n" - "}" + "}\n" + + "vec2 interpolate(ivec2 arr[4], float x) {\n" + " float x1m = 1. - x;\n" + " return x1m * x1m * x1m * arr[0] +" + " 3 * x1m * x1m * x * arr[1] +" + " 3 * x1m * x * x * arr[2] +" + " x * x * x * arr[3];\n" + "}\n" "void main() {\n" " float y = fract(texCoord.y);\n" - " float lin = y / ceil(y);\n" - " vec2 mixedTransform = mix(oldTransform[0], transform[0], lin);\n" - " vec2 mixedOffset = mix(oldOffset, offset, lin);\n" + " float lin = 0.5 - y / ceil(y) * 0.25;\n" + " vec2 mixedTransform = interpolate(transform, lin);\n" + " vec2 mixedOffset = interpolate(offset, lin);\n" " gl_FragColor = fetchTile(ivec2(mixedTransform * texCoord.x + mixedOffset));\n" "}"; @@ -192,7 +199,7 @@ static const char* const _composite = " ivec3 outflags = ivec3(0, 0, 0);\n" " if (inflags.x < oldFlags.x) {\n" " outflags = inflags;\n" - " if ((inflags.y & 1) == 1 && (oldFlags.y & 2) == 2) {\n" + " if (inflags.z == 1 && (inflags.y & 1) == 1 && (oldFlags.y & 2) == 2) {\n" " vec4 oldpix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" " pix *= blend.x;\n" " pix += oldpix * blend.y;\n" @@ -369,6 +376,7 @@ void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) { glRenderer->paletteDirty = true; glRenderer->vramDirty = 0xFFFFFF; + glRenderer->firstAffine = -1; } void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) { @@ -633,6 +641,23 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } glBindFramebuffer(GL_FRAMEBUFFER, 0); + if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) { + if (glRenderer->firstAffine < 0) { + memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine)); + memcpy(&glRenderer->bg[3].affine[3], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine)); + memcpy(&glRenderer->bg[2].affine[2], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine)); + memcpy(&glRenderer->bg[3].affine[2], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine)); + memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine)); + memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine)); + glRenderer->firstAffine = y; + } else if (y - glRenderer->firstAffine == 1) { + memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine)); + memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine)); + } + } else { + glRenderer->firstAffine = -1; + } + unsigned priority; for (priority = 4; priority--;) { if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) { @@ -674,6 +699,10 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) { + memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[2], sizeof(struct GBAVideoGLAffine)); + memcpy(&glRenderer->bg[3].affine[3], &glRenderer->bg[3].affine[2], sizeof(struct GBAVideoGLAffine)); + memcpy(&glRenderer->bg[2].affine[2], &glRenderer->bg[2].affine[1], sizeof(struct GBAVideoGLAffine)); + memcpy(&glRenderer->bg[3].affine[2], &glRenderer->bg[3].affine[1], sizeof(struct GBAVideoGLAffine)); memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine)); memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine)); @@ -685,7 +714,12 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) { - UNUSED(renderer); + struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + glRenderer->firstAffine = -1; + glRenderer->bg[2].affine[0].sx = glRenderer->bg[2].refx; + glRenderer->bg[2].affine[0].sy = glRenderer->bg[2].refy; + glRenderer->bg[3].affine[0].sx = glRenderer->bg[3].refx; + glRenderer->bg[3].affine[0].sy = glRenderer->bg[3].refy; glFlush(); } @@ -845,14 +879,32 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, glUniform1i(3, background->screenBase); glUniform1i(4, background->charBase); glUniform1i(5, background->size); - glUniform2i(6, background->affine[0].sx, background->affine[0].sy); - glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { background->affine[0].dx, background->affine[0].dy, background->affine[0].dmx, background->affine[0].dmy }); if (renderer->scale > 1) { - glUniform2i(7, background->affine[1].sx, background->affine[1].sy); - glUniformMatrix2fv(9, 1, GL_FALSE, (GLfloat[]) { background->affine[1].dx, background->affine[1].dy, background->affine[1].dmx, background->affine[1].dmy }); + glUniform2iv(6, 4, (GLint[]) { + background->affine[0].sx, background->affine[0].sy, + background->affine[1].sx, background->affine[1].sy, + background->affine[2].sx, background->affine[2].sy, + background->affine[3].sx, background->affine[3].sy, + }); + glUniform2iv(10, 4, (GLint[]) { + background->affine[0].dx, background->affine[0].dy, + background->affine[1].dx, background->affine[1].dy, + background->affine[2].dx, background->affine[2].dy, + background->affine[3].dx, background->affine[3].dy, + }); } else { - glUniform2i(7, background->affine[0].sx, background->affine[0].sy); - glUniformMatrix2fv(9, 1, GL_FALSE, (GLfloat[]) { background->affine[0].dx, background->affine[0].dy, background->affine[0].dmx, background->affine[0].dmy }); + glUniform2iv(6, 4, (GLint[]) { + background->affine[0].sx, background->affine[0].sy, + background->affine[0].sx, background->affine[0].sy, + background->affine[0].sx, background->affine[0].sy, + background->affine[0].sx, background->affine[0].sy, + }); + glUniform2iv(10, 4, (GLint[]) { + background->affine[0].dx, background->affine[0].dy, + background->affine[0].dx, background->affine[0].dy, + background->affine[0].dx, background->affine[0].dy, + background->affine[0].dx, background->affine[0].dy, + }); } glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); From 62f70379f6817cc3c0ae06d49bf2937ddd4a4bd6 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 12 May 2019 20:21:02 -0700 Subject: [PATCH 17/44] GBA Video: GL sprite initial work --- include/mgba/internal/gba/renderers/common.h | 25 ++ include/mgba/internal/gba/renderers/gl.h | 15 +- .../internal/gba/renderers/video-software.h | 9 +- src/gba/core.c | 5 +- src/gba/renderers/common.c | 33 +++ src/gba/renderers/gl.c | 252 +++++++++++++----- src/gba/renderers/video-software.c | 32 +-- 7 files changed, 265 insertions(+), 106 deletions(-) create mode 100644 include/mgba/internal/gba/renderers/common.h create mode 100644 src/gba/renderers/common.c diff --git a/include/mgba/internal/gba/renderers/common.h b/include/mgba/internal/gba/renderers/common.h new file mode 100644 index 000000000..e90b1f350 --- /dev/null +++ b/include/mgba/internal/gba/renderers/common.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2013-2019 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 GBA_RENDERER_COMMON_H +#define GBA_RENDERER_COMMON_H + +#include + +CXX_GUARD_START + +#include + +struct GBAVideoRendererSprite { + struct GBAObj obj; + int16_t y; + int16_t endY; +}; + +int GBAVideoRendererCleanOAM(struct GBAObj* oam, struct GBAVideoRendererSprite* sprites, int offsetY); + +CXX_GUARD_END + +#endif \ No newline at end of file diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index 8da5583e1..636f3bf05 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -13,6 +13,7 @@ CXX_GUARD_START #include #include #include +#include #include #ifdef USE_EPOXY @@ -61,11 +62,23 @@ struct GBAVideoGLBackground { struct GBAVideoGLAffine affine[4]; }; +enum { + GBA_GL_FBO_OBJ = 0, + GBA_GL_FBO_COMPOSITE = 1, + + GBA_GL_TEX_OBJ_COLOR = 0, + GBA_GL_TEX_OBJ_FLAGS = 1, + GBA_GL_TEX_COMPOSITE_FLAGS = 2, +}; + struct GBAVideoGLRenderer { struct GBAVideoRenderer d; struct GBAVideoGLBackground bg[4]; + int oamMax; + struct GBAVideoRendererSprite sprites[128]; + GLuint fbo[2]; GLuint layers[3]; @@ -81,7 +94,7 @@ struct GBAVideoGLRenderer { unsigned vramDirty; GLuint bgProgram[6]; - GLuint objProgram; + GLuint objProgram[4]; GLuint compositeProgram; diff --git a/include/mgba/internal/gba/renderers/video-software.h b/include/mgba/internal/gba/renderers/video-software.h index 3012cc10f..87e0addba 100644 --- a/include/mgba/internal/gba/renderers/video-software.h +++ b/include/mgba/internal/gba/renderers/video-software.h @@ -13,14 +13,9 @@ CXX_GUARD_START #include #include #include +#include #include -struct GBAVideoSoftwareSprite { - struct GBAObj obj; - int y; - int endY; -}; - struct GBAVideoSoftwareBackground { unsigned index; int enabled; @@ -140,7 +135,7 @@ struct GBAVideoSoftwareRenderer { int oamDirty; int oamMax; - struct GBAVideoSoftwareSprite sprites[128]; + struct GBAVideoRendererSprite sprites[128]; int16_t objOffsetX; int16_t objOffsetY; diff --git a/src/gba/core.c b/src/gba/core.c index 2c6207d8b..5284a04b9 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -263,10 +263,7 @@ static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* con static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) { struct GBACore* gbacore = (struct GBACore*) core; int fakeBool; - int scale = 1; - if (mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) { - scale = gbacore->glRenderer.scale; - } + int scale = gbacore->glRenderer.scale; *width = GBA_VIDEO_HORIZONTAL_PIXELS * scale; *height = GBA_VIDEO_VERTICAL_PIXELS * scale; diff --git a/src/gba/renderers/common.c b/src/gba/renderers/common.c new file mode 100644 index 000000000..9065a6267 --- /dev/null +++ b/src/gba/renderers/common.c @@ -0,0 +1,33 @@ +/* Copyright (c) 2013-2019 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 + +#include + +int GBAVideoRendererCleanOAM(struct GBAObj* oam, struct GBAVideoRendererSprite* sprites, int offsetY) { + int i; + int oamMax = 0; + for (i = 0; i < 128; ++i) { + struct GBAObj obj; + LOAD_16LE(obj.a, 0, &oam[i].a); + LOAD_16LE(obj.b, 0, &oam[i].b); + LOAD_16LE(obj.c, 0, &oam[i].c); + if (GBAObjAttributesAIsTransformed(obj.a) || !GBAObjAttributesAIsDisable(obj.a)) { + int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(obj.a) * 4 + GBAObjAttributesBGetSize(obj.b)][1]; + if (GBAObjAttributesAIsTransformed(obj.a)) { + height <<= GBAObjAttributesAGetDoubleSize(obj.a); + } + if (GBAObjAttributesAGetY(obj.a) < GBA_VIDEO_VERTICAL_PIXELS || GBAObjAttributesAGetY(obj.a) + height >= VIDEO_VERTICAL_TOTAL_PIXELS) { + int y = GBAObjAttributesAGetY(obj.a) + offsetY; + sprites[oamMax].y = y; + sprites[oamMax].endY = y + height; + sprites[oamMax].obj = obj; + ++oamMax; + } + } + } + return oamMax; +} \ No newline at end of file diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 7e10e9ab6..597248310 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -30,12 +30,15 @@ static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint1 static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value); static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value); +static void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GBAObj* sprite, int y, int spriteY); static void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); static void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); static void GBAVideoGLRendererDrawBackgroundMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); static void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); static void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); +static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, int y, int priority, int flags); + #define TEST_LAYER_ENABLED(X) !renderer->disableBG[X] && glRenderer->bg[X].enabled == 4 && glRenderer->bg[X].priority == priority static const GLchar* const _gl3Header = @@ -44,13 +47,13 @@ static const GLchar* const _gl3Header = static const char* const _vertexShader = "attribute vec2 position;\n" "uniform ivec2 loc;\n" - "const ivec2 maxPos = ivec2(240, 160);\n" + "uniform ivec2 maxPos;\n" "varying vec2 texCoord;\n" "void main() {\n" - " vec2 local = (position * loc.x + vec2(0, loc.y)) / vec2(1., maxPos.y);\n" - " gl_Position = vec4(local * 2. - 1., 0., 1.);\n" - " texCoord = local * maxPos.xy;\n" + " vec2 local = vec2(position.x, float(position.y * loc.x + loc.y) / abs(maxPos.y));\n" + " gl_Position = vec4((local * 2. - 1.) * sign(maxPos), 0., 1.);\n" + " texCoord = local * abs(maxPos);\n" "}"; static const char* const _renderTile16 = @@ -60,10 +63,9 @@ static const char* const _renderTile16 = " int entry = int(halfrow[3 - (localCoord.x & 3)] * 15.9);\n" " vec4 color = texelFetch(palette, ivec2(entry, paletteId), 0);\n" " if (entry == 0) {\n" - " color.a = 0;\n" - " } else {\n" - " color.a = 1;\n" + " discard;\n" " }\n" + " color.a = 1;\n" " return color;\n" "}"; @@ -74,11 +76,10 @@ static const char* const _renderTile256 = " int entry = int(halfrow[3 - 2 * (localCoord.x & 1)] * 15.9);\n" " int pal2 = int(halfrow[2 - 2 * (localCoord.x & 1)] * 15.9);\n" " vec4 color = texelFetch(palette, ivec2(entry, pal2 + (paletteId & 16)), 0);\n" - " if (pal2 > 0 || entry > 0) {\n" - " color.a = 1.;\n" - " } else {\n" - " color.a = 0.;\n" + " if (pal2 + entry == 0) {\n" + " discard;\n" " }\n" + " color.a = 1.;\n" " return color;\n" "}"; @@ -179,6 +180,26 @@ static const char* const _renderMode2 = " gl_FragColor = fetchTile(ivec2(mixedTransform * texCoord.x + mixedOffset));\n" "}"; +static const char* const _renderObjNoTransform = + "varying vec2 texCoord;\n" + "uniform sampler2D vram;\n" + "uniform sampler2D palette;\n" + "uniform int charBase;\n" + "uniform int stride;\n" + "uniform int localPalette;\n" + "uniform ivec3 inflags;\n" + "out vec4 color;\n" + "out vec3 flags;\n" + "const vec3 flagCoeff = vec3(32., 8., 4.);\n" + + "vec4 renderTile(int tile, int paletteId, ivec2 localCoord);\n" + + "void main() {\n" + " ivec2 coord = ivec2(texCoord);\n" + " color = renderTile((coord.x >> 3) + (coord.y >> 3) * stride, 16 + localPalette, coord & 7);\n" + " flags = inflags / flagCoeff;\n" + "}"; + static const char* const _composite = "varying vec2 texCoord;\n" "uniform ivec3 inflags;\n" @@ -186,20 +207,21 @@ static const char* const _composite = "uniform vec3 blend;\n" "uniform sampler2D layer;\n" "uniform sampler2D oldLayer;\n" - "uniform sampler2D buffer;\n" + "uniform sampler2D oldFlags;\n" "out vec4 color;\n" "out vec3 flags;\n" + "const vec3 flagCoeff = vec3(32., 8., 4.);\n" "void main() {\n" " vec4 pix = texelFetch(layer, ivec2(texCoord * scale), 0);\n" " if (pix.a == 0) {\n" " discard;\n" " }\n" - " ivec3 oldFlags = ivec3(texelFetch(buffer, ivec2(texCoord * scale), 0).xyz * vec3(32., 4., 1.));\n" + " ivec3 oflags = ivec3(texelFetch(oldFlags, ivec2(texCoord * scale), 0).xyz * flagCoeff);\n" " ivec3 outflags = ivec3(0, 0, 0);\n" - " if (inflags.x < oldFlags.x) {\n" + " if (inflags.x < oflags.x) {\n" " outflags = inflags;\n" - " if (inflags.z == 1 && (inflags.y & 1) == 1 && (oldFlags.y & 2) == 2) {\n" + " if (inflags.z == 1 && (inflags.y & 1) == 1 && (oflags.y & 2) == 2) {\n" " vec4 oldpix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" " pix *= blend.x;\n" " pix += oldpix * blend.y;\n" @@ -208,7 +230,7 @@ static const char* const _composite = " pix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" " }\n" " color = pix;\n" - " flags = outflags / vec3(32., 4., 1.);\n" + " flags = outflags / flagCoeff;\n" "}"; static const GLint _vertices[] = { @@ -240,7 +262,7 @@ void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) { renderer->scale = 1; } -void _compileBackground(struct GBAVideoGLRenderer* glRenderer, GLuint program, const char** shaderBuffer, int shaderBufferLines, GLuint vs, char* log) { +void _compileShader(struct GBAVideoGLRenderer* glRenderer, GLuint program, const char** shaderBuffer, int shaderBufferLines, GLuint vs, char* log) { GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); glAttachShader(program, vs); glAttachShader(program, fs); @@ -279,7 +301,24 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]); + glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], 0); + + glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], 0); + + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]); glBindTexture(GL_TEXTURE_2D, glRenderer->outputTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -288,13 +327,13 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->outputTex, 0); - glBindTexture(GL_TEXTURE_2D, glRenderer->layers[2]); + glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[2], 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS], 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -315,7 +354,10 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { } glRenderer->compositeProgram = glCreateProgram(); - glRenderer->objProgram = glCreateProgram(); + glRenderer->objProgram[0] = glCreateProgram(); + glRenderer->objProgram[1] = glCreateProgram(); + glRenderer->objProgram[2] = glCreateProgram(); + glRenderer->objProgram[3] = glCreateProgram(); glRenderer->bgProgram[0] = glCreateProgram(); glRenderer->bgProgram[1] = glCreateProgram(); glRenderer->bgProgram[2] = glCreateProgram(); @@ -339,21 +381,26 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { shaderBuffer[1] = _renderMode0; shaderBuffer[2] = _renderTile16; - _compileBackground(glRenderer, glRenderer->bgProgram[0], shaderBuffer, 3, vs, log); + _compileShader(glRenderer, glRenderer->bgProgram[0], shaderBuffer, 3, vs, log); shaderBuffer[2] = _renderTile256; - _compileBackground(glRenderer, glRenderer->bgProgram[1], shaderBuffer, 3, vs, log); + _compileShader(glRenderer, glRenderer->bgProgram[1], shaderBuffer, 3, vs, log); shaderBuffer[1] = _renderMode2; shaderBuffer[2] = _fetchTileOverflow; - _compileBackground(glRenderer, glRenderer->bgProgram[2], shaderBuffer, 3, vs, log); + _compileShader(glRenderer, glRenderer->bgProgram[2], shaderBuffer, 3, vs, log); shaderBuffer[2] = _fetchTileNoOverflow; - _compileBackground(glRenderer, glRenderer->bgProgram[3], shaderBuffer, 3, vs, log); + _compileShader(glRenderer, glRenderer->bgProgram[3], shaderBuffer, 3, vs, log); + + shaderBuffer[1] = _renderObjNoTransform; + + shaderBuffer[2] = _renderTile16; + _compileShader(glRenderer, glRenderer->objProgram[0], shaderBuffer, 3, vs, log); shaderBuffer[1] = _composite; - _compileBackground(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log); + _compileShader(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log); glBindFragDataLocation(glRenderer->compositeProgram, 0, "color"); glBindFragDataLocation(glRenderer->compositeProgram, 1, "flags"); @@ -369,6 +416,19 @@ void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { glDeleteTextures(1, &glRenderer->paletteTex); glDeleteTextures(1, &glRenderer->vramTex); glDeleteTextures(1, &glRenderer->oamTex); + + glDeleteProgram(glRenderer->bgProgram[0]); + glDeleteProgram(glRenderer->bgProgram[1]); + glDeleteProgram(glRenderer->bgProgram[2]); + glDeleteProgram(glRenderer->bgProgram[3]); + glDeleteProgram(glRenderer->bgProgram[4]); + glDeleteProgram(glRenderer->bgProgram[5]); + glDeleteProgram(glRenderer->bgProgram[6]); + glDeleteProgram(glRenderer->objProgram[0]); + glDeleteProgram(glRenderer->objProgram[1]); + glDeleteProgram(glRenderer->objProgram[2]); + glDeleteProgram(glRenderer->objProgram[3]); + glDeleteProgram(glRenderer->compositeProgram); } void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) { @@ -610,11 +670,6 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 16, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, glRenderer->d.palette); glRenderer->paletteDirty = false; } - if (glRenderer->oamDirty) { - glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 4, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, glRenderer->d.oam); - glRenderer->oamDirty = false; - } int i; for (i = 0; i < 24; ++i) { if (!(glRenderer->vramDirty & (1 << i))) { @@ -628,16 +683,25 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { uint32_t backdrop = M_RGB5_TO_RGB8(renderer->palette[0]); glClearColor(((backdrop >> 16) & 0xFF) / 256., ((backdrop >> 8) & 0xFF) / 256., (backdrop & 0xFF) / 256., 0.f); - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]); glEnable(GL_SCISSOR_TEST); glScissor(0, y * glRenderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, glRenderer->scale); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); if (y == 0) { glDrawBuffer(GL_COLOR_ATTACHMENT1); - glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2)) / 4.f, 0, 1); + glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2)) / 8.f, 0, 1); glClear(GL_COLOR_BUFFER_BIT); glDrawBuffer(GL_COLOR_ATTACHMENT0); + + glClearColor(0, 0, 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]); + glClear(GL_COLOR_BUFFER_BIT); + + for (i = 0; i < 4; ++i) { + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo); + glClear(GL_COLOR_BUFFER_BIT); + } } glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -658,6 +722,27 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { glRenderer->firstAffine = -1; } + glEnable(GL_SCISSOR_TEST); + int spriteLayers = 0; + if (GBARegisterDISPCNTIsObjEnable(glRenderer->dispcnt) && !glRenderer->d.disableOBJ) { + if (glRenderer->oamDirty) { + glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 4, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, glRenderer->d.oam); + glRenderer->oamMax = GBAVideoRendererCleanOAM(glRenderer->d.oam->obj, glRenderer->sprites, 0); + glRenderer->oamDirty = false; + } + int i; + for (i = glRenderer->oamMax; i--;) { + struct GBAVideoRendererSprite* sprite = &glRenderer->sprites[i]; + if ((y < sprite->y && (sprite->endY - 256 < 0 || y >= sprite->endY - 256)) || y >= sprite->endY) { + continue; + } + + GBAVideoGLRendererDrawSprite(glRenderer, &sprite->obj, y, sprite->y); + spriteLayers |= 1 << GBAObjAttributesCGetPriority(sprite->obj.c); + } + } + unsigned priority; for (priority = 4; priority--;) { if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) { @@ -697,6 +782,7 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } } } + _compositeLayer(glRenderer, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], y, 0, 0); if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) { memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[2], sizeof(struct GBAVideoGLAffine)); @@ -804,34 +890,72 @@ static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, u renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value); } -static void _compositeLayer(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y, int flags) { +static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, int y, int priority, int flags) { if ((y & 0x1F) != 0x1F) { return; } - glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[1]); + glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_COMPOSITE]); glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); - glScissor(0, (y * renderer->scale) % (0x20 * renderer->scale), GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale); + glScissor(0, (y & ~0x1F) * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale); glUseProgram(renderer->compositeProgram); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, background->tex); + glBindTexture(GL_TEXTURE_2D, tex); glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, renderer->outputTex); glActiveTexture(GL_TEXTURE0 + 2); - glBindTexture(GL_TEXTURE_2D, renderer->layers[2]); + glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]); glUniform2i(0, 0x20, y & ~0x1F); - glUniform3i(1, (background->priority << 3) + (background->index << 1) + 1, flags, renderer->blendEffect); - glUniform1i(2, renderer->scale); - glUniform3f(3, renderer->blda / 16.f, renderer->bldb / 16.f, renderer->bldy / 16.f); - glUniform1i(4, 0); - glUniform1i(5, 1); - glUniform1i(6, 2); + glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); + glUniform3i(2, priority, flags, renderer->blendEffect); + glUniform1i(3, renderer->scale); + glUniform3f(4, renderer->blda / 16.f, renderer->bldb / 16.f, renderer->bldy / 16.f); + glUniform1i(5, 0); + glUniform1i(6, 1); + glUniform1i(7, 2); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); + glBindFramebuffer(GL_FRAMEBUFFER, 0); } +void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GBAObj* sprite, int y, int spriteY) { + int width = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][0]; + int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][1]; + int32_t x = (uint32_t) GBAObjAttributesBGetX(sprite->b) << 23; + x >>= 23; + + int align = GBAObjAttributesAIs256Color(sprite->a) && !GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt); + unsigned charBase = (BASE_TILE >> 1) + (GBAObjAttributesCGetTile(sprite->c) & ~align) * 0x10; + int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> 3) : (0x10 >> !GBAObjAttributesAIs256Color(sprite->a)); + + if (spriteY + height >= 256) { + spriteY -= 256; + } + + glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OBJ]); + glViewport(x * renderer->scale, spriteY * renderer->scale, width * renderer->scale, height * renderer->scale); + glScissor(x * renderer->scale, y * renderer->scale, width * renderer->scale, renderer->scale); + glUseProgram(renderer->objProgram[0]); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, renderer->vramTex); + glActiveTexture(GL_TEXTURE0 + 1); + glBindTexture(GL_TEXTURE_2D, renderer->paletteTex); + glUniform2i(0, 1, y - spriteY); + glUniform2i(1, GBAObjAttributesBIsHFlip(sprite->b) ? -width : width, height); + glUniform1i(2, 0); + glUniform1i(3, 1); + glUniform1i(4, charBase); + glUniform1i(5, stride); + glUniform1i(6, GBAObjAttributesCGetPalette(sprite->c)); + glUniform3i(7, GBAObjAttributesCGetPriority(sprite->c) << 3, 0, 0); + glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); + glEnableVertexAttribArray(0); + glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });} + void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { int inY = y + background->y; int yBase = inY & 0xFF; @@ -849,19 +973,18 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, renderer->paletteTex); glUniform2i(0, 1, y); - glUniform1i(1, 0); - glUniform1i(2, 1); - glUniform1i(3, background->screenBase); - glUniform1i(4, background->charBase); - glUniform1i(5, background->size); - glUniform2i(6, background->x, yBase - y); + glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); + glUniform1i(2, 0); + glUniform1i(3, 1); + glUniform1i(4, background->screenBase); + glUniform1i(5, background->charBase); + glUniform1i(6, background->size); + glUniform2i(7, background->x, yBase - y); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - _compositeLayer(renderer, background, y, background->target1 | (background->target2 * 2)); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); + _compositeLayer(renderer, background->tex, y, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2)); } void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { @@ -874,32 +997,33 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, renderer->paletteTex); glUniform2i(0, 1, y); - glUniform1i(1, 0); - glUniform1i(2, 1); - glUniform1i(3, background->screenBase); - glUniform1i(4, background->charBase); - glUniform1i(5, background->size); + glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); + glUniform1i(2, 0); + glUniform1i(3, 1); + glUniform1i(4, background->screenBase); + glUniform1i(5, background->charBase); + glUniform1i(6, background->size); if (renderer->scale > 1) { - glUniform2iv(6, 4, (GLint[]) { + glUniform2iv(7, 4, (GLint[]) { background->affine[0].sx, background->affine[0].sy, background->affine[1].sx, background->affine[1].sy, background->affine[2].sx, background->affine[2].sy, background->affine[3].sx, background->affine[3].sy, }); - glUniform2iv(10, 4, (GLint[]) { + glUniform2iv(11, 4, (GLint[]) { background->affine[0].dx, background->affine[0].dy, background->affine[1].dx, background->affine[1].dy, background->affine[2].dx, background->affine[2].dy, background->affine[3].dx, background->affine[3].dy, }); } else { - glUniform2iv(6, 4, (GLint[]) { + glUniform2iv(7, 4, (GLint[]) { background->affine[0].sx, background->affine[0].sy, background->affine[0].sx, background->affine[0].sy, background->affine[0].sx, background->affine[0].sy, background->affine[0].sx, background->affine[0].sy, }); - glUniform2iv(10, 4, (GLint[]) { + glUniform2iv(11, 4, (GLint[]) { background->affine[0].dx, background->affine[0].dy, background->affine[0].dx, background->affine[0].dy, background->affine[0].dx, background->affine[0].dy, @@ -910,7 +1034,5 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - _compositeLayer(renderer, background, y, background->target1 | (background->target2 * 2)); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); + _compositeLayer(renderer, background->tex, y, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2)); } \ No newline at end of file diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c index 46f6cb958..0e5d7dd5f 100644 --- a/src/gba/renderers/video-software.c +++ b/src/gba/renderers/video-software.c @@ -36,7 +36,6 @@ static void GBAVideoSoftwareRendererWriteBGY_LO(struct GBAVideoSoftwareBackgroun static void GBAVideoSoftwareRendererWriteBGY_HI(struct GBAVideoSoftwareBackground* bg, uint16_t value); static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer, uint16_t value); -static void _cleanOAM(struct GBAVideoSoftwareRenderer* renderer); static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y); static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer); @@ -498,32 +497,6 @@ static void _breakWindowInner(struct GBAVideoSoftwareRenderer* softwareRenderer, #endif } -static void _cleanOAM(struct GBAVideoSoftwareRenderer* renderer) { - int i; - int oamMax = 0; - for (i = 0; i < 128; ++i) { - struct GBAObj obj; - LOAD_16(obj.a, 0, &renderer->d.oam->obj[i].a); - LOAD_16(obj.b, 0, &renderer->d.oam->obj[i].b); - LOAD_16(obj.c, 0, &renderer->d.oam->obj[i].c); - if (GBAObjAttributesAIsTransformed(obj.a) || !GBAObjAttributesAIsDisable(obj.a)) { - int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(obj.a) * 4 + GBAObjAttributesBGetSize(obj.b)][1]; - if (GBAObjAttributesAIsTransformed(obj.a)) { - height <<= GBAObjAttributesAGetDoubleSize(obj.a); - } - if (GBAObjAttributesAGetY(obj.a) < GBA_VIDEO_VERTICAL_PIXELS || GBAObjAttributesAGetY(obj.a) + height >= VIDEO_VERTICAL_TOTAL_PIXELS) { - int y = GBAObjAttributesAGetY(obj.a) + renderer->objOffsetY; - renderer->sprites[oamMax].y = y; - renderer->sprites[oamMax].endY = y + height; - renderer->sprites[oamMax].obj = obj; - ++oamMax; - } - } - } - renderer->oamMax = oamMax; - renderer->oamDirty = 0; -} - static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer; @@ -821,14 +794,15 @@ static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) { int spriteLayers = 0; if (GBARegisterDISPCNTIsObjEnable(renderer->dispcnt) && !renderer->d.disableOBJ) { if (renderer->oamDirty) { - _cleanOAM(renderer); + renderer->oamMax = GBAVideoRendererCleanOAM(renderer->d.oam->obj, renderer->sprites, renderer->objOffsetY); + renderer->oamDirty = false; } renderer->spriteCyclesRemaining = GBARegisterDISPCNTIsHblankIntervalFree(renderer->dispcnt) ? OBJ_HBLANK_FREE_LENGTH : OBJ_LENGTH; int mosaicV = GBAMosaicControlGetObjV(renderer->mosaic) + 1; int mosaicY = y - (y % mosaicV); int i; for (i = 0; i < renderer->oamMax; ++i) { - struct GBAVideoSoftwareSprite* sprite = &renderer->sprites[i]; + struct GBAVideoRendererSprite* sprite = &renderer->sprites[i]; int localY = y; renderer->end = 0; if (GBAObjAttributesAIsMosaic(sprite->obj.a)) { From bd69c9fb26365f8876a20b385e9b9de94ed80feb Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 12 May 2019 22:24:21 -0700 Subject: [PATCH 18/44] GBA Video: Add per-pixel flags in GL --- include/mgba/internal/gba/renderers/gl.h | 1 + src/gba/renderers/gl.c | 127 +++++++++++++++-------- 2 files changed, 86 insertions(+), 42 deletions(-) diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index 636f3bf05..df6c8c6e7 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -42,6 +42,7 @@ struct GBAVideoGLAffine { struct GBAVideoGLBackground { GLuint fbo; GLuint tex; + GLuint flags; unsigned index; int enabled; diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 597248310..2a0e6067a 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -37,7 +37,7 @@ static void GBAVideoGLRendererDrawBackgroundMode3(struct GBAVideoGLRenderer* ren static void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); static void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); -static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, int y, int priority, int flags); +static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int y); #define TEST_LAYER_ENABLED(X) !renderer->disableBG[X] && glRenderer->bg[X].enabled == 4 && glRenderer->bg[X].priority == priority @@ -76,7 +76,7 @@ static const char* const _renderTile256 = " int entry = int(halfrow[3 - 2 * (localCoord.x & 1)] * 15.9);\n" " int pal2 = int(halfrow[2 - 2 * (localCoord.x & 1)] * 15.9);\n" " vec4 color = texelFetch(palette, ivec2(entry, pal2 + (paletteId & 16)), 0);\n" - " if (pal2 + entry == 0) {\n" + " if ((pal2 | entry) == 0) {\n" " discard;\n" " }\n" " color.a = 1.;\n" @@ -91,6 +91,10 @@ static const char* const _renderMode0 = "uniform int charBase;\n" "uniform int size;\n" "uniform ivec2 offset;\n" + "uniform ivec3 inflags;\n" + "out vec4 color;\n" + "out vec3 flags;\n" + "const vec3 flagCoeff = vec3(32., 8., 4.);\n" "vec4 renderTile(int tile, int paletteId, ivec2 localCoord);\n" @@ -102,15 +106,16 @@ static const char* const _renderMode0 = " coord.x &= 255;\n" " int mapAddress = screenBase + (coord.x >> 3) + (coord.y >> 3) * 32;\n" " vec4 map = texelFetch(vram, ivec2(mapAddress & 255, mapAddress >> 8), 0);\n" - " int flags = int(map.g * 15.9);\n" - " if ((flags & 4) == 4) {\n" + " int tileFlags = int(map.g * 15.9);\n" + " if ((tileFlags & 4) == 4) {\n" " coord.x ^= 7;\n" " }\n" - " if ((flags & 8) == 8) {\n" + " if ((tileFlags & 8) == 8) {\n" " coord.y ^= 7;\n" " }\n" - " int tile = int(map.a * 15.9) + int(map.b * 15.9) * 16 + (flags & 0x3) * 256;\n" - " gl_FragColor = renderTile(tile, int(map.r * 15.9), coord & 7);\n" + " int tile = int(map.a * 15.9) + int(map.b * 15.9) * 16 + (tileFlags & 0x3) * 256;\n" + " color = renderTile(tile, int(map.r * 15.9), coord & 7);\n" + " flags = inflags / flagCoeff;\n" "}"; static const char* const _fetchTileOverflow = @@ -125,9 +130,7 @@ static const char* const _fetchTileNoOverflow = " int sizeAdjusted = (0x8000 << size) - 1;\n" " ivec2 outerCoord = coord & ~sizeAdjusted;\n" " if ((outerCoord.x | outerCoord.y) != 0) {\n" - " vec4 color = texelFetch(palette, ivec2(0, 0), 0);\n" - " color.a = 0;\n" - " return color;\n" + " discard;\n" " }\n" " return renderTile(coord);\n" "}"; @@ -139,8 +142,12 @@ static const char* const _renderMode2 = "uniform int screenBase;\n" "uniform int charBase;\n" "uniform int size;\n" + "uniform ivec3 inflags;\n" "uniform ivec2[4] offset;\n" "uniform ivec2[4] transform;\n" + "out vec4 color;\n" + "out vec3 flags;\n" + "const vec3 flagCoeff = vec3(32., 8., 4.);\n" "precision highp float;\n" "precision highp int;\n" @@ -156,11 +163,10 @@ static const char* const _renderMode2 = " int entry = int(halfrow[3 - ((coord.x >> 7) & 2)] * 15.9);\n" " int pal2 = int(halfrow[2 - ((coord.x >> 7) & 2)] * 15.9);\n" " vec4 color = texelFetch(palette, ivec2(entry, pal2), 0);\n" - " if (pal2 > 0 || entry > 0) {\n" - " color.a = 1.;\n" - " } else {\n" - " color.a = 0.;\n" + " if ((pal2 | entry) == 0) {\n" + " discard;\n" " }\n" + " color.a = 1.;\n" " return color;\n" "}\n" @@ -177,7 +183,8 @@ static const char* const _renderMode2 = " float lin = 0.5 - y / ceil(y) * 0.25;\n" " vec2 mixedTransform = interpolate(transform, lin);\n" " vec2 mixedOffset = interpolate(offset, lin);\n" - " gl_FragColor = fetchTile(ivec2(mixedTransform * texCoord.x + mixedOffset));\n" + " color = fetchTile(ivec2(mixedTransform * texCoord.x + mixedOffset));\n" + " flags = inflags / flagCoeff;\n" "}"; static const char* const _renderObjNoTransform = @@ -202,10 +209,10 @@ static const char* const _renderObjNoTransform = static const char* const _composite = "varying vec2 texCoord;\n" - "uniform ivec3 inflags;\n" "uniform int scale;\n" "uniform vec3 blend;\n" "uniform sampler2D layer;\n" + "uniform sampler2D layerFlags;\n" "uniform sampler2D oldLayer;\n" "uniform sampler2D oldFlags;\n" "out vec4 color;\n" @@ -217,6 +224,7 @@ static const char* const _composite = " if (pix.a == 0) {\n" " discard;\n" " }\n" + " ivec3 inflags = ivec3(texelFetch(layerFlags, ivec2(texCoord * scale), 0).xyz * flagCoeff);\n" " ivec3 oflags = ivec3(texelFetch(oldFlags, ivec2(texCoord * scale), 0).xyz * flagCoeff);\n" " ivec3 outflags = ivec3(0, 0, 0);\n" " if (inflags.x < oflags.x) {\n" @@ -228,6 +236,7 @@ static const char* const _composite = " }\n" " } else {\n" " pix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" + " outflags = oflags;\n" " }\n" " color = pix;\n" " flags = outflags / flagCoeff;\n" @@ -278,6 +287,8 @@ void _compileShader(struct GBAVideoGLRenderer* glRenderer, GLuint program, const mLOG(GBA_VIDEO, ERROR, "Program link failure: %s", log); } glDeleteShader(fs); + glBindFragDataLocation(program, 0, "color"); + glBindFragDataLocation(program, 1, "flags"); } void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { @@ -342,7 +353,9 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glRenderer->bg[i].index = i; glGenFramebuffers(1, &glRenderer->bg[i].fbo); glGenTextures(1, &glRenderer->bg[i].tex); + glGenTextures(1, &glRenderer->bg[i].flags); glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo); + glBindTexture(GL_TEXTURE_2D, glRenderer->bg[i].tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -350,6 +363,15 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->bg[i].tex, 0); + + glBindTexture(GL_TEXTURE_2D, glRenderer->bg[i].flags); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->bg[i].flags, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -399,10 +421,11 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { shaderBuffer[2] = _renderTile16; _compileShader(glRenderer, glRenderer->objProgram[0], shaderBuffer, 3, vs, log); + shaderBuffer[2] = _renderTile256; + _compileShader(glRenderer, glRenderer->objProgram[2], shaderBuffer, 3, vs, log); + shaderBuffer[1] = _composite; _compileShader(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log); - glBindFragDataLocation(glRenderer->compositeProgram, 0, "color"); - glBindFragDataLocation(glRenderer->compositeProgram, 1, "flags"); glDeleteShader(vs); @@ -686,22 +709,30 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]); glEnable(GL_SCISSOR_TEST); glScissor(0, y * glRenderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, glRenderer->scale); + glDrawBuffer(GL_COLOR_ATTACHMENT0); glClear(GL_COLOR_BUFFER_BIT); - glDisable(GL_SCISSOR_TEST); if (y == 0) { + glDisable(GL_SCISSOR_TEST); glDrawBuffer(GL_COLOR_ATTACHMENT1); glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2)) / 8.f, 0, 1); glClear(GL_COLOR_BUFFER_BIT); - glDrawBuffer(GL_COLOR_ATTACHMENT0); - + glClearColor(0, 0, 0, 0); glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glClear(GL_COLOR_BUFFER_BIT); + glDrawBuffer(GL_COLOR_ATTACHMENT1); glClear(GL_COLOR_BUFFER_BIT); for (i = 0; i < 4; ++i) { glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo); - glClear(GL_COLOR_BUFFER_BIT); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glClear(GL_COLOR_BUFFER_BIT); + glDrawBuffer(GL_COLOR_ATTACHMENT1); + glClear(GL_COLOR_BUFFER_BIT); } + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glEnable(GL_SCISSOR_TEST); } glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -722,7 +753,6 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { glRenderer->firstAffine = -1; } - glEnable(GL_SCISSOR_TEST); int spriteLayers = 0; if (GBARegisterDISPCNTIsObjEnable(glRenderer->dispcnt) && !glRenderer->d.disableOBJ) { if (glRenderer->oamDirty) { @@ -743,6 +773,7 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } } + _compositeLayer(glRenderer, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], y); unsigned priority; for (priority = 4; priority--;) { if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) { @@ -782,7 +813,6 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } } } - _compositeLayer(glRenderer, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], y, 0, 0); if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) { memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[2], sizeof(struct GBAVideoGLAffine)); @@ -890,7 +920,7 @@ static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, u renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value); } -static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, int y, int priority, int flags) { +static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int y) { if ((y & 0x1F) != 0x1F) { return; } @@ -901,17 +931,19 @@ static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, int glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); glActiveTexture(GL_TEXTURE0 + 1); - glBindTexture(GL_TEXTURE_2D, renderer->outputTex); + glBindTexture(GL_TEXTURE_2D, flags); glActiveTexture(GL_TEXTURE0 + 2); + glBindTexture(GL_TEXTURE_2D, renderer->outputTex); + glActiveTexture(GL_TEXTURE0 + 3); glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]); glUniform2i(0, 0x20, y & ~0x1F); glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); - glUniform3i(2, priority, flags, renderer->blendEffect); - glUniform1i(3, renderer->scale); - glUniform3f(4, renderer->blda / 16.f, renderer->bldb / 16.f, renderer->bldy / 16.f); - glUniform1i(5, 0); - glUniform1i(6, 1); - glUniform1i(7, 2); + glUniform1i(2, renderer->scale); + glUniform3f(3, renderer->blda / 16.f, renderer->bldb / 16.f, renderer->bldy / 16.f); + glUniform1i(4, 0); + glUniform1i(5, 1); + glUniform1i(6, 2); + glUniform1i(7, 3); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); @@ -928,16 +960,20 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB int align = GBAObjAttributesAIs256Color(sprite->a) && !GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt); unsigned charBase = (BASE_TILE >> 1) + (GBAObjAttributesCGetTile(sprite->c) & ~align) * 0x10; - int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> 3) : (0x10 >> !GBAObjAttributesAIs256Color(sprite->a)); + int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> 3) : (0x40 >> !GBAObjAttributesAIs256Color(sprite->a)); if (spriteY + height >= 256) { spriteY -= 256; } + if (GBAObjAttributesBIsVFlip(sprite->b)) { + spriteY = (y - height) + (y - spriteY) + 1; + } + glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OBJ]); glViewport(x * renderer->scale, spriteY * renderer->scale, width * renderer->scale, height * renderer->scale); glScissor(x * renderer->scale, y * renderer->scale, width * renderer->scale, renderer->scale); - glUseProgram(renderer->objProgram[0]); + glUseProgram(renderer->objProgram[GBAObjAttributesAIs256Color(sprite->a) ? 2 : 0]); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, renderer->vramTex); glActiveTexture(GL_TEXTURE0 + 1); @@ -949,12 +985,13 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB glUniform1i(4, charBase); glUniform1i(5, stride); glUniform1i(6, GBAObjAttributesCGetPalette(sprite->c)); - glUniform3i(7, GBAObjAttributesCGetPriority(sprite->c) << 3, 0, 0); + glUniform3i(7, GBAObjAttributesCGetPriority(sprite->c) << 3, (renderer->target1Obj | (renderer->target2Obj * 2)) / 8.f, 0); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });} + glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); +} void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { int inY = y + background->y; @@ -980,11 +1017,14 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, glUniform1i(5, background->charBase); glUniform1i(6, background->size); glUniform2i(7, background->x, yBase - y); + glUniform3i(8, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2), renderer->blendEffect); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); + glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); - _compositeLayer(renderer, background->tex, y, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2)); + _compositeLayer(renderer, background->tex, background->flags, y); } void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { @@ -1003,27 +1043,28 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, glUniform1i(4, background->screenBase); glUniform1i(5, background->charBase); glUniform1i(6, background->size); + glUniform3i(7, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2), renderer->blendEffect); if (renderer->scale > 1) { - glUniform2iv(7, 4, (GLint[]) { + glUniform2iv(8, 4, (GLint[]) { background->affine[0].sx, background->affine[0].sy, background->affine[1].sx, background->affine[1].sy, background->affine[2].sx, background->affine[2].sy, background->affine[3].sx, background->affine[3].sy, }); - glUniform2iv(11, 4, (GLint[]) { + glUniform2iv(12, 4, (GLint[]) { background->affine[0].dx, background->affine[0].dy, background->affine[1].dx, background->affine[1].dy, background->affine[2].dx, background->affine[2].dy, background->affine[3].dx, background->affine[3].dy, }); } else { - glUniform2iv(7, 4, (GLint[]) { + glUniform2iv(8, 4, (GLint[]) { background->affine[0].sx, background->affine[0].sy, background->affine[0].sx, background->affine[0].sy, background->affine[0].sx, background->affine[0].sy, background->affine[0].sx, background->affine[0].sy, }); - glUniform2iv(11, 4, (GLint[]) { + glUniform2iv(12, 4, (GLint[]) { background->affine[0].dx, background->affine[0].dy, background->affine[0].dx, background->affine[0].dy, background->affine[0].dx, background->affine[0].dy, @@ -1032,7 +1073,9 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, } glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); + glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); - _compositeLayer(renderer, background->tex, y, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2)); + _compositeLayer(renderer, background->tex, background->flags, y); } \ No newline at end of file From c15dedf3f44f76abe87a40fe02db6f9a26f80123 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 13 May 2019 00:55:26 -0700 Subject: [PATCH 19/44] GBA Video: Add transformed objects to GL --- include/mgba/internal/gba/renderers/gl.h | 2 +- src/gba/renderers/gl.c | 48 +++++++++++++++++------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index df6c8c6e7..5af071000 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -95,7 +95,7 @@ struct GBAVideoGLRenderer { unsigned vramDirty; GLuint bgProgram[6]; - GLuint objProgram[4]; + GLuint objProgram[2]; GLuint compositeProgram; diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 2a0e6067a..58a650bd0 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -187,7 +187,7 @@ static const char* const _renderMode2 = " flags = inflags / flagCoeff;\n" "}"; -static const char* const _renderObjNoTransform = +static const char* const _renderObj = "varying vec2 texCoord;\n" "uniform sampler2D vram;\n" "uniform sampler2D palette;\n" @@ -195,6 +195,8 @@ static const char* const _renderObjNoTransform = "uniform int stride;\n" "uniform int localPalette;\n" "uniform ivec3 inflags;\n" + "uniform mat2x2 transform;\n" + "uniform ivec4 dims;\n" "out vec4 color;\n" "out vec3 flags;\n" "const vec3 flagCoeff = vec3(32., 8., 4.);\n" @@ -202,7 +204,10 @@ static const char* const _renderObjNoTransform = "vec4 renderTile(int tile, int paletteId, ivec2 localCoord);\n" "void main() {\n" - " ivec2 coord = ivec2(texCoord);\n" + " ivec2 coord = ivec2(transform * (texCoord - dims.zw / 2) + dims.xy / 2);\n" + " if ((coord & ~(dims.xy - 1)) != ivec2(0, 0)) {\n" + " discard;\n" + " }\n" " color = renderTile((coord.x >> 3) + (coord.y >> 3) * stride, 16 + localPalette, coord & 7);\n" " flags = inflags / flagCoeff;\n" "}"; @@ -378,8 +383,6 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glRenderer->compositeProgram = glCreateProgram(); glRenderer->objProgram[0] = glCreateProgram(); glRenderer->objProgram[1] = glCreateProgram(); - glRenderer->objProgram[2] = glCreateProgram(); - glRenderer->objProgram[3] = glCreateProgram(); glRenderer->bgProgram[0] = glCreateProgram(); glRenderer->bgProgram[1] = glCreateProgram(); glRenderer->bgProgram[2] = glCreateProgram(); @@ -416,13 +419,13 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { shaderBuffer[2] = _fetchTileNoOverflow; _compileShader(glRenderer, glRenderer->bgProgram[3], shaderBuffer, 3, vs, log); - shaderBuffer[1] = _renderObjNoTransform; + shaderBuffer[1] = _renderObj; shaderBuffer[2] = _renderTile16; _compileShader(glRenderer, glRenderer->objProgram[0], shaderBuffer, 3, vs, log); shaderBuffer[2] = _renderTile256; - _compileShader(glRenderer, glRenderer->objProgram[2], shaderBuffer, 3, vs, log); + _compileShader(glRenderer, glRenderer->objProgram[1], shaderBuffer, 3, vs, log); shaderBuffer[1] = _composite; _compileShader(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log); @@ -449,8 +452,6 @@ void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { glDeleteProgram(glRenderer->bgProgram[6]); glDeleteProgram(glRenderer->objProgram[0]); glDeleteProgram(glRenderer->objProgram[1]); - glDeleteProgram(glRenderer->objProgram[2]); - glDeleteProgram(glRenderer->objProgram[3]); glDeleteProgram(glRenderer->compositeProgram); } @@ -966,26 +967,45 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB spriteY -= 256; } - if (GBAObjAttributesBIsVFlip(sprite->b)) { + if (!GBAObjAttributesAIsTransformed(sprite->a) && GBAObjAttributesBIsVFlip(sprite->b)) { spriteY = (y - height) + (y - spriteY) + 1; } + int totalWidth = width; + int totalHeight = height; + if (GBAObjAttributesAIsTransformed(sprite->a) && GBAObjAttributesAIsDoubleSize(sprite->a)) { + totalWidth <<= 1; + totalHeight <<= 1; + } + glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OBJ]); - glViewport(x * renderer->scale, spriteY * renderer->scale, width * renderer->scale, height * renderer->scale); - glScissor(x * renderer->scale, y * renderer->scale, width * renderer->scale, renderer->scale); - glUseProgram(renderer->objProgram[GBAObjAttributesAIs256Color(sprite->a) ? 2 : 0]); + glViewport(x * renderer->scale, spriteY * renderer->scale, totalWidth * renderer->scale, totalHeight * renderer->scale); + glScissor(x * renderer->scale, y * renderer->scale, totalWidth * renderer->scale, renderer->scale); + glUseProgram(renderer->objProgram[GBAObjAttributesAGet256Color(sprite->a)]); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, renderer->vramTex); glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, renderer->paletteTex); glUniform2i(0, 1, y - spriteY); - glUniform2i(1, GBAObjAttributesBIsHFlip(sprite->b) ? -width : width, height); + glUniform2i(1, (GBAObjAttributesBIsHFlip(sprite->b) && !GBAObjAttributesAIsTransformed(sprite->a)) ? -totalWidth : totalWidth, totalHeight); glUniform1i(2, 0); glUniform1i(3, 1); glUniform1i(4, charBase); glUniform1i(5, stride); glUniform1i(6, GBAObjAttributesCGetPalette(sprite->c)); - glUniform3i(7, GBAObjAttributesCGetPriority(sprite->c) << 3, (renderer->target1Obj | (renderer->target2Obj * 2)) / 8.f, 0); + glUniform3i(7, GBAObjAttributesCGetPriority(sprite->c) << 3, renderer->target1Obj | (renderer->target2Obj * 2), 0); + if (GBAObjAttributesAIsTransformed(sprite->a)) { + struct GBAOAMMatrix mat; + LOAD_16(mat.a, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].a); + LOAD_16(mat.b, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].b); + LOAD_16(mat.c, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].c); + LOAD_16(mat.d, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].d); + + glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { mat.a / 256.f, mat.c / 256.f, mat.b / 256.f, mat.d / 256.f }); + } else { + glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { 1.f, 0, 0, 1.f }); + } + glUniform4i(9, width, height, totalWidth, totalHeight); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); From 509c80abad8221564a0bfade571d868e9e8247af Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 13 May 2019 01:16:35 -0700 Subject: [PATCH 20/44] GBA Video: GL semitransparent OBJs --- src/gba/renderers/gl.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 58a650bd0..82d2b9c6a 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -240,8 +240,14 @@ static const char* const _composite = " pix += oldpix * blend.y;\n" " }\n" " } else {\n" - " pix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" " outflags = oflags;\n" + " vec4 oldpix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" + " if (oflags.z == 1 && (oflags.y & 1) == 1 && (inflags.y & 2) == 2) {\n" + " pix *= blend.y;\n" + " pix += oldpix * blend.x;\n" + " } else {\n" + " pix = oldpix;\n" + " }\n" " }\n" " color = pix;\n" " flags = outflags / flagCoeff;\n" @@ -993,7 +999,7 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB glUniform1i(4, charBase); glUniform1i(5, stride); glUniform1i(6, GBAObjAttributesCGetPalette(sprite->c)); - glUniform3i(7, GBAObjAttributesCGetPriority(sprite->c) << 3, renderer->target1Obj | (renderer->target2Obj * 2), 0); + glUniform3i(7, GBAObjAttributesCGetPriority(sprite->c) << 3, (renderer->target1Obj || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) | (renderer->target2Obj * 2), GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT ? BLEND_ALPHA : renderer->blendEffect); if (GBAObjAttributesAIsTransformed(sprite->a)) { struct GBAOAMMatrix mat; LOAD_16(mat.a, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].a); From b865d8e479ec16288fa51a40ebf20a91c74dd57d Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 13 May 2019 02:18:46 -0700 Subject: [PATCH 21/44] SDL: Fix initialization ordering issues --- src/platform/sdl/main.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/platform/sdl/main.c b/src/platform/sdl/main.c index 450e1868a..21e4459b7 100644 --- a/src/platform/sdl/main.c +++ b/src/platform/sdl/main.c @@ -90,6 +90,12 @@ int main(int argc, char** argv) { freeArguments(&args); return 1; } + + if (!renderer.core->init(renderer.core)) { + freeArguments(&args); + return 1; + } + renderer.core->desiredVideoDimensions(renderer.core, &renderer.width, &renderer.height); #ifdef BUILD_GL mSDLGLCreate(&renderer); @@ -106,11 +112,6 @@ int main(int argc, char** argv) { opts.width = renderer.width * renderer.ratio; opts.height = renderer.height * renderer.ratio; - if (!renderer.core->init(renderer.core)) { - freeArguments(&args); - return 1; - } - struct mCheatDevice* device = NULL; if (args.cheatsFile && (device = renderer.core->cheatDevice(renderer.core))) { struct VFile* vf = VFileOpen(args.cheatsFile, O_RDONLY); From 424fbddfea8cdbb424838db3289bea835f2786b5 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 13 May 2019 13:46:25 -0700 Subject: [PATCH 22/44] GBA Video: GL better blending and finalization --- include/mgba/internal/gba/renderers/gl.h | 15 +- src/gba/renderers/gl.c | 246 +++++++++++++---------- 2 files changed, 152 insertions(+), 109 deletions(-) diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index 5af071000..b5917f0e1 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -66,10 +66,14 @@ struct GBAVideoGLBackground { enum { GBA_GL_FBO_OBJ = 0, GBA_GL_FBO_COMPOSITE = 1, + GBA_GL_FBO_OUTPUT = 2, GBA_GL_TEX_OBJ_COLOR = 0, GBA_GL_TEX_OBJ_FLAGS = 1, - GBA_GL_TEX_COMPOSITE_FLAGS = 2, + GBA_GL_TEX_COMPOSITE_COLOR = 2, + GBA_GL_TEX_COMPOSITE_FLAGS = 3, + GBA_GL_TEX_COMPOSITE_OLD_COLOR = 4, + GBA_GL_TEX_COMPOSITE_OLD_FLAGS = 5, }; struct GBAVideoGLRenderer { @@ -78,19 +82,17 @@ struct GBAVideoGLRenderer { struct GBAVideoGLBackground bg[4]; int oamMax; + bool oamDirty; struct GBAVideoRendererSprite sprites[128]; - GLuint fbo[2]; - GLuint layers[3]; + GLuint fbo[3]; + GLuint layers[6]; GLuint outputTex; GLuint paletteTex; bool paletteDirty; - GLuint oamTex; - bool oamDirty; - GLuint vramTex; unsigned vramDirty; @@ -98,6 +100,7 @@ struct GBAVideoGLRenderer { GLuint objProgram[2]; GLuint compositeProgram; + GLuint finalizeProgram; GBARegisterDISPCNT dispcnt; diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 82d2b9c6a..4c51b27cc 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -38,6 +38,7 @@ static void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* ren static void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int y); +static void _finalizeLayers(struct GBAVideoGLRenderer* renderer, int y); #define TEST_LAYER_ENABLED(X) !renderer->disableBG[X] && glRenderer->bg[X].enabled == 4 && glRenderer->bg[X].priority == priority @@ -91,10 +92,10 @@ static const char* const _renderMode0 = "uniform int charBase;\n" "uniform int size;\n" "uniform ivec2 offset;\n" - "uniform ivec3 inflags;\n" + "uniform ivec4 inflags;\n" "out vec4 color;\n" - "out vec3 flags;\n" - "const vec3 flagCoeff = vec3(32., 8., 4.);\n" + "out vec4 flags;\n" + "const vec4 flagCoeff = vec4(32., 32., 16., 16.);\n" "vec4 renderTile(int tile, int paletteId, ivec2 localCoord);\n" @@ -142,12 +143,12 @@ static const char* const _renderMode2 = "uniform int screenBase;\n" "uniform int charBase;\n" "uniform int size;\n" - "uniform ivec3 inflags;\n" + "uniform ivec4 inflags;\n" "uniform ivec2[4] offset;\n" "uniform ivec2[4] transform;\n" "out vec4 color;\n" - "out vec3 flags;\n" - "const vec3 flagCoeff = vec3(32., 8., 4.);\n" + "out vec4 flags;\n" + "const vec4 flagCoeff = vec4(32., 32., 16., 16.);\n" "precision highp float;\n" "precision highp int;\n" @@ -194,12 +195,12 @@ static const char* const _renderObj = "uniform int charBase;\n" "uniform int stride;\n" "uniform int localPalette;\n" - "uniform ivec3 inflags;\n" + "uniform ivec4 inflags;\n" "uniform mat2x2 transform;\n" "uniform ivec4 dims;\n" "out vec4 color;\n" - "out vec3 flags;\n" - "const vec3 flagCoeff = vec3(32., 8., 4.);\n" + "out vec4 flags;\n" + "const vec4 flagCoeff = vec4(32., 32., 16., 16.);\n" "vec4 renderTile(int tile, int paletteId, ivec2 localCoord);\n" @@ -215,42 +216,66 @@ static const char* const _renderObj = static const char* const _composite = "varying vec2 texCoord;\n" "uniform int scale;\n" - "uniform vec3 blend;\n" "uniform sampler2D layer;\n" "uniform sampler2D layerFlags;\n" "uniform sampler2D oldLayer;\n" - "uniform sampler2D oldFlags;\n" + "uniform sampler2D oldLayerFlags;\n" + "uniform sampler2D oldOldFlags;\n" "out vec4 color;\n" - "out vec3 flags;\n" - "const vec3 flagCoeff = vec3(32., 8., 4.);\n" + "out vec4 flags;\n" + "out vec4 oldColor;\n" + "out vec4 oldFlags;\n" + "const vec4 flagCoeff = vec4(32., 32., 16., 16.);\n" "void main() {\n" " vec4 pix = texelFetch(layer, ivec2(texCoord * scale), 0);\n" " if (pix.a == 0) {\n" " discard;\n" " }\n" - " ivec3 inflags = ivec3(texelFetch(layerFlags, ivec2(texCoord * scale), 0).xyz * flagCoeff);\n" - " ivec3 oflags = ivec3(texelFetch(oldFlags, ivec2(texCoord * scale), 0).xyz * flagCoeff);\n" - " ivec3 outflags = ivec3(0, 0, 0);\n" - " if (inflags.x < oflags.x) {\n" - " outflags = inflags;\n" - " if (inflags.z == 1 && (inflags.y & 1) == 1 && (oflags.y & 2) == 2) {\n" - " vec4 oldpix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" - " pix *= blend.x;\n" - " pix += oldpix * blend.y;\n" + " ivec4 inflags = ivec4(texelFetch(layerFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" + " ivec4 oflags = ivec4(texelFetch(oldLayerFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" + " if (inflags.x >= oflags.x) {\n" + " ivec4 ooflags = ivec4(texelFetch(oldOldFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" + " if (inflags.x >= ooflags.x) {\n" + " discard;\n" " }\n" + " oldFlags = inflags / flagCoeff;\n" + " flags = oflags / flagCoeff;\n" + " oldColor = pix;\n" + " color = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" " } else {\n" - " outflags = oflags;\n" - " vec4 oldpix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" - " if (oflags.z == 1 && (oflags.y & 1) == 1 && (inflags.y & 2) == 2) {\n" - " pix *= blend.y;\n" - " pix += oldpix * blend.x;\n" - " } else {\n" - " pix = oldpix;\n" - " }\n" + " color = pix;\n" + " oldColor = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" + " flags = inflags / flagCoeff;\n" + " oldFlags = oflags / flagCoeff;\n" " }\n" - " color = pix;\n" - " flags = outflags / flagCoeff;\n" + "}"; + +static const char* const _finalize = + "varying vec2 texCoord;\n" + "uniform int scale;\n" + "uniform sampler2D layer;\n" + "uniform sampler2D layerFlags;\n" + "uniform sampler2D oldLayer;\n" + "uniform sampler2D oldFlags;\n" + "const vec4 flagCoeff = vec4(32., 32., 16., 16.);\n" + + "void main() {\n" + " vec4 pix = texelFetch(layer, ivec2(texCoord * scale), 0);\n" + " ivec4 inflags = ivec4(texelFetch(layerFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" + " if ((inflags.y & 13) == 5) {\n" + " ivec4 oflags = ivec4(texelFetch(oldFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" + " if ((oflags.y & 2) == 2) {\n" + " vec4 oldpix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" + " pix *= inflags.z / 16.;\n" + " pix += oldpix * oflags.w / 16.;\n" + " }\n" + " } else if ((inflags.y & 13) == 9) {\n" + " pix += (1. - pix) * inflags.z / 16.;\n" + " } else if ((inflags.y & 13) == 13) {\n" + " pix -= pix * inflags.z / 16.;\n" + " }\n" + " gl_FragColor = pix;\n" "}"; static const GLint _vertices[] = { @@ -302,10 +327,20 @@ void _compileShader(struct GBAVideoGLRenderer* glRenderer, GLuint program, const glBindFragDataLocation(program, 1, "flags"); } +static void _initFramebufferTexture(GLuint tex, GLenum format, GLenum attachment, int scale) { + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, format, GBA_VIDEO_HORIZONTAL_PIXELS * scale, GBA_VIDEO_VERTICAL_PIXELS * scale, 0, format, GL_UNSIGNED_BYTE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex, 0); +} + void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; - glGenFramebuffers(2, glRenderer->fbo); - glGenTextures(3, glRenderer->layers); + glGenFramebuffers(3, glRenderer->fbo); + glGenTextures(6, glRenderer->layers); glGenTextures(1, &glRenderer->paletteTex); glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex); @@ -318,44 +353,18 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 256, 192, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0); - glGenTextures(1, &glRenderer->oamTex); - glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]); - glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], 0); - - glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], 0); + _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale); + _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], GL_RGBA, GL_COLOR_ATTACHMENT1, glRenderer->scale); glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]); - glBindTexture(GL_TEXTURE_2D, glRenderer->outputTex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->outputTex, 0); + _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_COMPOSITE_COLOR], GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale); + _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS], GL_RGBA, GL_COLOR_ATTACHMENT1, glRenderer->scale); + _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_COMPOSITE_OLD_COLOR], GL_RGBA, GL_COLOR_ATTACHMENT2, glRenderer->scale); + _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_COMPOSITE_OLD_FLAGS], GL_RGBA, GL_COLOR_ATTACHMENT3, glRenderer->scale); - glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS], 0); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OUTPUT]); + _initFramebufferTexture(glRenderer->outputTex, GL_RGB, GL_COLOR_ATTACHMENT0, glRenderer->scale); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -366,27 +375,13 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glGenTextures(1, &glRenderer->bg[i].tex); glGenTextures(1, &glRenderer->bg[i].flags); glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo); - - glBindTexture(GL_TEXTURE_2D, glRenderer->bg[i].tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->bg[i].tex, 0); - - glBindTexture(GL_TEXTURE_2D, glRenderer->bg[i].flags); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->bg[i].flags, 0); - + _initFramebufferTexture(glRenderer->bg[i].tex, GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale); + _initFramebufferTexture(glRenderer->bg[i].flags, GL_RGBA, GL_COLOR_ATTACHMENT1, glRenderer->scale); glBindFramebuffer(GL_FRAMEBUFFER, 0); } glRenderer->compositeProgram = glCreateProgram(); + glRenderer->finalizeProgram = glCreateProgram(); glRenderer->objProgram[0] = glCreateProgram(); glRenderer->objProgram[1] = glCreateProgram(); glRenderer->bgProgram[0] = glCreateProgram(); @@ -435,6 +430,11 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { shaderBuffer[1] = _composite; _compileShader(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log); + glBindFragDataLocation(glRenderer->compositeProgram, 2, "oldColor"); + glBindFragDataLocation(glRenderer->compositeProgram, 3, "oldFlags"); + + shaderBuffer[1] = _finalize; + _compileShader(glRenderer, glRenderer->finalizeProgram, shaderBuffer, 2, vs, log); glDeleteShader(vs); @@ -444,10 +444,9 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; glDeleteFramebuffers(2, glRenderer->fbo); - glDeleteTextures(3, glRenderer->layers); + glDeleteTextures(6, glRenderer->layers); glDeleteTextures(1, &glRenderer->paletteTex); glDeleteTextures(1, &glRenderer->vramTex); - glDeleteTextures(1, &glRenderer->oamTex); glDeleteProgram(glRenderer->bgProgram[0]); glDeleteProgram(glRenderer->bgProgram[1]); @@ -615,9 +614,7 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, if (value > 0x10) { value = 0x10; } - if (glRenderer->bldy != value) { - glRenderer->bldy = value; - } + glRenderer->bldy = value; break; case REG_WIN0H: /*glRenderer->winN[0].h.end = value; @@ -721,10 +718,14 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { if (y == 0) { glDisable(GL_SCISSOR_TEST); glDrawBuffer(GL_COLOR_ATTACHMENT1); - glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2)) / 8.f, 0, 1); + glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2) | (glRenderer->blendEffect * 4)) / 32.f, + (glRenderer->blendEffect == BLEND_ALPHA ? glRenderer->blda : glRenderer->bldy) / 16.f, glRenderer->bldb / 16.f); glClear(GL_COLOR_BUFFER_BIT); glClearColor(0, 0, 0, 0); + glDrawBuffer(GL_COLOR_ATTACHMENT3); + glClear(GL_COLOR_BUFFER_BIT); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]); glDrawBuffer(GL_COLOR_ATTACHMENT0); glClear(GL_COLOR_BUFFER_BIT); @@ -763,8 +764,6 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { int spriteLayers = 0; if (GBARegisterDISPCNTIsObjEnable(glRenderer->dispcnt) && !glRenderer->d.disableOBJ) { if (glRenderer->oamDirty) { - glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 4, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, glRenderer->d.oam); glRenderer->oamMax = GBAVideoRendererCleanOAM(glRenderer->d.oam->obj, glRenderer->sprites, 0); glRenderer->oamDirty = false; } @@ -820,6 +819,8 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } } } + _finalizeLayers(glRenderer, y); + if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) { memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[2], sizeof(struct GBAVideoGLAffine)); @@ -940,25 +941,56 @@ static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLu glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, flags); glActiveTexture(GL_TEXTURE0 + 2); - glBindTexture(GL_TEXTURE_2D, renderer->outputTex); + glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_COLOR]); glActiveTexture(GL_TEXTURE0 + 3); glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]); + glActiveTexture(GL_TEXTURE0 + 4); + glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_OLD_FLAGS]); glUniform2i(0, 0x20, y & ~0x1F); glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); glUniform1i(2, renderer->scale); - glUniform3f(3, renderer->blda / 16.f, renderer->bldb / 16.f, renderer->bldy / 16.f); - glUniform1i(4, 0); - glUniform1i(5, 1); - glUniform1i(6, 2); - glUniform1i(7, 3); + glUniform1i(3, 0); + glUniform1i(4, 1); + glUniform1i(5, 2); + glUniform1i(6, 3); + glUniform1i(7, 4); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); - glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); + glDrawBuffers(4, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 }); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); glBindFramebuffer(GL_FRAMEBUFFER, 0); } +void _finalizeLayers(struct GBAVideoGLRenderer* renderer, int y) { + if ((y & 0x1F) != 0x1F) { + return; + } + glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OUTPUT]); + glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); + glScissor(0, (y & ~0x1F) * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale); + glUseProgram(renderer->finalizeProgram); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_COLOR]); + glActiveTexture(GL_TEXTURE0 + 1); + glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]); + glActiveTexture(GL_TEXTURE0 + 2); + glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_OLD_COLOR]); + glActiveTexture(GL_TEXTURE0 + 3); + glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_OLD_FLAGS]); + glUniform2i(0, 0x20, y & ~0x1F); + glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); + glUniform1i(2, renderer->scale); + glUniform1i(3, 0); + glUniform1i(4, 1); + glUniform1i(5, 2); + glUniform1i(6, 3); + glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); + glEnableVertexAttribArray(0); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GBAObj* sprite, int y, int spriteY) { int width = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][0]; int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][1]; @@ -984,6 +1016,8 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB totalHeight <<= 1; } + enum GBAVideoBlendEffect blendEffect = GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT ? BLEND_ALPHA : renderer->blendEffect; + glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OBJ]); glViewport(x * renderer->scale, spriteY * renderer->scale, totalWidth * renderer->scale, totalHeight * renderer->scale); glScissor(x * renderer->scale, y * renderer->scale, totalWidth * renderer->scale, renderer->scale); @@ -999,7 +1033,9 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB glUniform1i(4, charBase); glUniform1i(5, stride); glUniform1i(6, GBAObjAttributesCGetPalette(sprite->c)); - glUniform3i(7, GBAObjAttributesCGetPriority(sprite->c) << 3, (renderer->target1Obj || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) | (renderer->target2Obj * 2), GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT ? BLEND_ALPHA : renderer->blendEffect); + glUniform4i(7, GBAObjAttributesCGetPriority(sprite->c) << 3, + (renderer->target1Obj || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) | (renderer->target2Obj * 2) | (blendEffect * 4), + blendEffect == BLEND_ALPHA ? renderer->blda : renderer->bldy, renderer->bldb); if (GBAObjAttributesAIsTransformed(sprite->a)) { struct GBAOAMMatrix mat; LOAD_16(mat.a, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].a); @@ -1043,7 +1079,9 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, glUniform1i(5, background->charBase); glUniform1i(6, background->size); glUniform2i(7, background->x, yBase - y); - glUniform3i(8, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2), renderer->blendEffect); + glUniform4i(8, (background->priority << 3) + (background->index << 1) + 1, + background->target1 | (background->target2 * 2) | (renderer->blendEffect * 4), + renderer->blendEffect == BLEND_ALPHA ? renderer->blda : renderer->bldy, renderer->bldb); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); @@ -1069,7 +1107,9 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, glUniform1i(4, background->screenBase); glUniform1i(5, background->charBase); glUniform1i(6, background->size); - glUniform3i(7, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2), renderer->blendEffect); + glUniform4i(7, (background->priority << 3) + (background->index << 1) + 1, + background->target1 | (background->target2 * 2) | (renderer->blendEffect * 4), + renderer->blendEffect == BLEND_ALPHA ? renderer->blda : renderer->bldy, renderer->bldb); if (renderer->scale > 1) { glUniform2iv(8, 4, (GLint[]) { background->affine[0].sx, background->affine[0].sy, From a50ea97bce0445171fddd7ecedd11adb321c1780 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 13 May 2019 16:15:54 -0700 Subject: [PATCH 23/44] GBA Video: Initialize GL backgrounds better --- src/gba/renderers/gl.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 4c51b27cc..ef50347be 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -370,13 +370,34 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { int i; for (i = 0; i < 4; ++i) { - glRenderer->bg[i].index = i; - glGenFramebuffers(1, &glRenderer->bg[i].fbo); - glGenTextures(1, &glRenderer->bg[i].tex); - glGenTextures(1, &glRenderer->bg[i].flags); - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo); - _initFramebufferTexture(glRenderer->bg[i].tex, GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale); - _initFramebufferTexture(glRenderer->bg[i].flags, GL_RGBA, GL_COLOR_ATTACHMENT1, glRenderer->scale); + struct GBAVideoGLBackground* bg = &glRenderer->bg[i]; + bg->index = i; + bg->enabled = 0; + bg->priority = 0; + bg->charBase = 0; + bg->mosaic = 0; + bg->multipalette = 0; + bg->screenBase = 0; + bg->overflow = 0; + bg->size = 0; + bg->target1 = 0; + bg->target2 = 0; + bg->x = 0; + bg->y = 0; + bg->refx = 0; + bg->refy = 0; + bg->affine[0].dx = 256; + bg->affine[0].dmx = 0; + bg->affine[0].dy = 0; + bg->affine[0].dmy = 256; + bg->affine[0].sx = 0; + bg->affine[0].sy = 0; + glGenFramebuffers(1, &bg->fbo); + glGenTextures(1, &bg->tex); + glGenTextures(1, &bg->flags); + glBindFramebuffer(GL_FRAMEBUFFER, bg->fbo); + _initFramebufferTexture(bg->tex, GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale); + _initFramebufferTexture(bg->flags, GL_RGBA, GL_COLOR_ATTACHMENT1, glRenderer->scale); glBindFramebuffer(GL_FRAMEBUFFER, 0); } From 3e8bb42e9f745f69f2137f071cfdc8fda0f3d435 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 13 May 2019 18:07:03 -0700 Subject: [PATCH 24/44] GBA Video: Windows in GL --- include/mgba/internal/gba/renderers/gl.h | 21 +++- .../internal/gba/renderers/video-software.h | 9 +- include/mgba/internal/gba/video.h | 5 + src/gba/renderers/gl.c | 101 ++++++++++++------ 4 files changed, 94 insertions(+), 42 deletions(-) diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index b5917f0e1..c8a0391f9 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -66,14 +66,20 @@ struct GBAVideoGLBackground { enum { GBA_GL_FBO_OBJ = 0, GBA_GL_FBO_COMPOSITE = 1, - GBA_GL_FBO_OUTPUT = 2, + GBA_GL_FBO_WINDOW = 2, + GBA_GL_FBO_OUTPUT = 3, + GBA_GL_FBO_MAX +}; +enum { GBA_GL_TEX_OBJ_COLOR = 0, GBA_GL_TEX_OBJ_FLAGS = 1, GBA_GL_TEX_COMPOSITE_COLOR = 2, GBA_GL_TEX_COMPOSITE_FLAGS = 3, GBA_GL_TEX_COMPOSITE_OLD_COLOR = 4, GBA_GL_TEX_COMPOSITE_OLD_FLAGS = 5, + GBA_GL_TEX_WINDOW = 6, + GBA_GL_TEX_MAX }; struct GBAVideoGLRenderer { @@ -85,8 +91,8 @@ struct GBAVideoGLRenderer { bool oamDirty; struct GBAVideoRendererSprite sprites[128]; - GLuint fbo[3]; - GLuint layers[6]; + GLuint fbo[GBA_GL_FBO_MAX]; + GLuint layers[GBA_GL_TEX_MAX]; GLuint outputTex; @@ -115,6 +121,15 @@ struct GBAVideoGLRenderer { GBAMosaicControl mosaic; + struct GBAVideoGLWindowN { + struct GBAVideoWindowRegion h; + struct GBAVideoWindowRegion v; + GBAWindowControl control; + } winN[2]; + + GBAWindowControl winout; + GBAWindowControl objwin; + int firstAffine; int scale; diff --git a/include/mgba/internal/gba/renderers/video-software.h b/include/mgba/internal/gba/renderers/video-software.h index 87e0addba..47b8ddfb6 100644 --- a/include/mgba/internal/gba/renderers/video-software.h +++ b/include/mgba/internal/gba/renderers/video-software.h @@ -70,11 +70,6 @@ enum { #define IS_WRITABLE(PIXEL) ((PIXEL) & 0xFE000000) -struct WindowRegion { - uint8_t end; - uint8_t start; -}; - struct WindowControl { GBAWindowControl packed; int8_t priority; @@ -118,8 +113,8 @@ struct GBAVideoSoftwareRenderer { GBAMosaicControl mosaic; struct WindowN { - struct WindowRegion h; - struct WindowRegion v; + struct GBAVideoWindowRegion h; + struct GBAVideoWindowRegion v; struct WindowControl control; } winN[2]; diff --git a/include/mgba/internal/gba/video.h b/include/mgba/internal/gba/video.h index 699d2f238..ba8048ffd 100644 --- a/include/mgba/internal/gba/video.h +++ b/include/mgba/internal/gba/video.h @@ -97,6 +97,11 @@ union GBAOAM { uint16_t raw[512]; }; +struct GBAVideoWindowRegion { + uint8_t end; + uint8_t start; +}; + #define GBA_TEXT_MAP_TILE(MAP) ((MAP) & 0x03FF) #define GBA_TEXT_MAP_HFLIP(MAP) ((MAP) & 0x0400) #define GBA_TEXT_MAP_VFLIP(MAP) ((MAP) & 0x0800) diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index ef50347be..80450afcd 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -36,8 +36,9 @@ static void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* ren static void GBAVideoGLRendererDrawBackgroundMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); static void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); static void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); +static void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y); -static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int y); +static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int id, int y); static void _finalizeLayers(struct GBAVideoGLRenderer* renderer, int y); #define TEST_LAYER_ENABLED(X) !renderer->disableBG[X] && glRenderer->bg[X].enabled == 4 && glRenderer->bg[X].priority == priority @@ -216,11 +217,13 @@ static const char* const _renderObj = static const char* const _composite = "varying vec2 texCoord;\n" "uniform int scale;\n" + "uniform int layerId\n;" "uniform sampler2D layer;\n" "uniform sampler2D layerFlags;\n" "uniform sampler2D oldLayer;\n" "uniform sampler2D oldLayerFlags;\n" "uniform sampler2D oldOldFlags;\n" + "uniform sampler2D window;\n" "out vec4 color;\n" "out vec4 flags;\n" "out vec4 oldColor;\n" @@ -232,8 +235,15 @@ static const char* const _composite = " if (pix.a == 0) {\n" " discard;\n" " }\n" + " ivec2 windowFlags = ivec2(texelFetch(window, ivec2(texCoord * scale), 0).xy * 32.);\n" + " if (((windowFlags.x | (windowFlags.y << 4)) & layerId) != 0) {\n" + " discard;\n" + " }\n" " ivec4 inflags = ivec4(texelFetch(layerFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" " ivec4 oflags = ivec4(texelFetch(oldLayerFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" + " if ((windowFlags.y & 2) != 0) {\n" + " inflags.y = 0;\n" + " }\n" " if (inflags.x >= oflags.x) {\n" " ivec4 ooflags = ivec4(texelFetch(oldOldFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" " if (inflags.x >= ooflags.x) {\n" @@ -339,8 +349,8 @@ static void _initFramebufferTexture(GLuint tex, GLenum format, GLenum attachment void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; - glGenFramebuffers(3, glRenderer->fbo); - glGenTextures(6, glRenderer->layers); + glGenFramebuffers(GBA_GL_FBO_MAX, glRenderer->fbo); + glGenTextures(GBA_GL_TEX_MAX, glRenderer->layers); glGenTextures(1, &glRenderer->paletteTex); glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex); @@ -363,6 +373,9 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_COMPOSITE_OLD_COLOR], GL_RGBA, GL_COLOR_ATTACHMENT2, glRenderer->scale); _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_COMPOSITE_OLD_FLAGS], GL_RGBA, GL_COLOR_ATTACHMENT3, glRenderer->scale); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_WINDOW]); + _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_WINDOW], GL_RG, GL_COLOR_ATTACHMENT0, glRenderer->scale); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OUTPUT]); _initFramebufferTexture(glRenderer->outputTex, GL_RGB, GL_COLOR_ATTACHMENT0, glRenderer->scale); @@ -464,8 +477,8 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; - glDeleteFramebuffers(2, glRenderer->fbo); - glDeleteTextures(6, glRenderer->layers); + glDeleteFramebuffers(GBA_GL_FBO_MAX, glRenderer->fbo); + glDeleteTextures(GBA_GL_TEX_MAX, glRenderer->layers); glDeleteTextures(1, &glRenderer->paletteTex); glDeleteTextures(1, &glRenderer->vramTex); @@ -638,7 +651,7 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, glRenderer->bldy = value; break; case REG_WIN0H: - /*glRenderer->winN[0].h.end = value; + glRenderer->winN[0].h.end = value; glRenderer->winN[0].h.start = value >> 8; if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[0].h.start > glRenderer->winN[0].h.end) { glRenderer->winN[0].h.start = 0; @@ -648,10 +661,10 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) { glRenderer->winN[0].h.start = GBA_VIDEO_HORIZONTAL_PIXELS; } - }*/ + } break; case REG_WIN1H: - /*glRenderer->winN[1].h.end = value; + glRenderer->winN[1].h.end = value; glRenderer->winN[1].h.start = value >> 8; if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[1].h.start > glRenderer->winN[1].h.end) { glRenderer->winN[1].h.start = 0; @@ -661,10 +674,10 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) { glRenderer->winN[1].h.start = GBA_VIDEO_HORIZONTAL_PIXELS; } - }*/ + } break; case REG_WIN0V: - /*glRenderer->winN[0].v.end = value; + glRenderer->winN[0].v.end = value; glRenderer->winN[0].v.start = value >> 8; if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[0].v.start > glRenderer->winN[0].v.end) { glRenderer->winN[0].v.start = 0; @@ -674,10 +687,10 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS) { glRenderer->winN[0].v.start = GBA_VIDEO_VERTICAL_PIXELS; } - }*/ + } break; case REG_WIN1V: - /*glRenderer->winN[1].v.end = value; + glRenderer->winN[1].v.end = value; glRenderer->winN[1].v.start = value >> 8; if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[1].v.start > glRenderer->winN[1].v.end) { glRenderer->winN[1].v.start = 0; @@ -687,26 +700,23 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS) { glRenderer->winN[1].v.start = GBA_VIDEO_VERTICAL_PIXELS; } - }*/ + } break; case REG_WININ: value &= 0x3F3F; - //glRenderer->winN[0].control.packed = value; - //glRenderer->winN[1].control.packed = value >> 8; + glRenderer->winN[0].control = value; + glRenderer->winN[1].control = value >> 8; break; case REG_WINOUT: value &= 0x3F3F; - //glRenderer->winout.packed = value; - //glRenderer->objwin.packed = value >> 8; + glRenderer->winout = value; + glRenderer->objwin = value >> 8; break; case REG_MOSAIC: glRenderer->mosaic = value; break; - case REG_GREENSWP: - mLOG(GBA_VIDEO, STUB, "Stub video register write: 0x%03X", address); - break; default: - mLOG(GBA_VIDEO, GAME_ERROR, "Invalid video register: 0x%03X", address); + break; } return value; } @@ -800,7 +810,8 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } } - _compositeLayer(glRenderer, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], y); + GBAVideoGLRendererDrawWindow(glRenderer, y); + _compositeLayer(glRenderer, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], 4, y); unsigned priority; for (priority = 4; priority--;) { if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) { @@ -842,7 +853,6 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } _finalizeLayers(glRenderer, y); - if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) { memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[2], sizeof(struct GBAVideoGLAffine)); memcpy(&glRenderer->bg[3].affine[3], &glRenderer->bg[3].affine[2], sizeof(struct GBAVideoGLAffine)); @@ -949,7 +959,7 @@ static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, u renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value); } -static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int y) { +static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int id, int y) { if ((y & 0x1F) != 0x1F) { return; } @@ -967,14 +977,18 @@ static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLu glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]); glActiveTexture(GL_TEXTURE0 + 4); glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_OLD_FLAGS]); + glActiveTexture(GL_TEXTURE0 + 5); + glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_WINDOW]); glUniform2i(0, 0x20, y & ~0x1F); glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); glUniform1i(2, renderer->scale); - glUniform1i(3, 0); - glUniform1i(4, 1); - glUniform1i(5, 2); - glUniform1i(6, 3); - glUniform1i(7, 4); + glUniform1i(3, 1 << id); + glUniform1i(4, 0); + glUniform1i(5, 1); + glUniform1i(6, 2); + glUniform1i(7, 3); + glUniform1i(8, 4); + glUniform1i(9, 5); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawBuffers(4, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 }); @@ -1109,7 +1123,7 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); - _compositeLayer(renderer, background->tex, background->flags, y); + _compositeLayer(renderer, background->tex, background->flags, background->index, y); } void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { @@ -1164,5 +1178,28 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); - _compositeLayer(renderer, background->tex, background->flags, y); -} \ No newline at end of file + _compositeLayer(renderer, background->tex, background->flags, background->index, y); +} + +static void _clearWindow(GBAWindowControl window, int start, int end, int y, int scale) { + glScissor(start, y, end - start, scale); + window = ~window & 0xFF; + glClearColor((window & 0xF) / 32.f, (window >> 4) / 32.f, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); +} + +void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y) { + glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_WINDOW]); + if (!(renderer->dispcnt & 0xE000)) { + _clearWindow(0xFF, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, y * renderer->scale, renderer->scale); + } else { + _clearWindow(renderer->winout, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, y * renderer->scale, renderer->scale); + if (GBARegisterDISPCNTIsWin1Enable(renderer->dispcnt) && y >= renderer->winN[1].v.start && y < renderer->winN[1].v.end) { + _clearWindow(renderer->winN[1].control, renderer->winN[1].h.start * renderer->scale, renderer->winN[1].h.end * renderer->scale, y * renderer->scale, renderer->scale); + } + if (GBARegisterDISPCNTIsWin0Enable(renderer->dispcnt) && y >= renderer->winN[0].v.start && y < renderer->winN[0].v.end) { + _clearWindow(renderer->winN[0].control, renderer->winN[0].h.start * renderer->scale, renderer->winN[0].h.end * renderer->scale, y * renderer->scale, renderer->scale); + } + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} From 4e4e46117586ce99ea6536ed325aaa9ee8afcc5c Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 13 May 2019 21:32:34 -0700 Subject: [PATCH 25/44] GBA Video: Clean up GL uniforms --- include/mgba/internal/gba/renderers/gl.h | 44 ++++++ src/gba/renderers/gl.c | 193 +++++++++++++++++------ 2 files changed, 186 insertions(+), 51 deletions(-) diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index c8a0391f9..c5a09f24a 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -82,6 +82,46 @@ enum { GBA_GL_TEX_MAX }; +enum { + GBA_GL_VS_LOC = 0, + GBA_GL_VS_MAXPOS, + + GBA_GL_BG_VRAM = 2, + GBA_GL_BG_PALETTE, + GBA_GL_BG_SCREENBASE, + GBA_GL_BG_CHARBASE, + GBA_GL_BG_SIZE, + GBA_GL_BG_OFFSET, + GBA_GL_BG_INFLAGS, + GBA_GL_BG_TRANSFORM, + + GBA_GL_OBJ_VRAM = 2, + GBA_GL_OBJ_PALETTE, + GBA_GL_OBJ_CHARBASE, + GBA_GL_OBJ_STRIDE, + GBA_GL_OBJ_LOCALPALETTE, + GBA_GL_OBJ_INFLAGS, + GBA_GL_OBJ_TRANSFORM, + GBA_GL_OBJ_DIMS, + + GBA_GL_COMPOSITE_SCALE = 2, + GBA_GL_COMPOSITE_LAYERID, + GBA_GL_COMPOSITE_LAYER, + GBA_GL_COMPOSITE_LAYERFLAGS, + GBA_GL_COMPOSITE_OLDLAYER, + GBA_GL_COMPOSITE_OLDLAYERFLAGS, + GBA_GL_COMPOSITE_OLDOLDFLAGS, + GBA_GL_COMPOSITE_WINDOW, + + GBA_GL_FINALIZE_SCALE = 2, + GBA_GL_FINALIZE_LAYER, + GBA_GL_FINALIZE_LAYERFLAGS, + GBA_GL_FINALIZE_OLDLAYER, + GBA_GL_FINALIZE_OLDFLAGS, + + GBA_GL_UNIFORM_MAX = 12 +}; + struct GBAVideoGLRenderer { struct GBAVideoRenderer d; @@ -103,10 +143,14 @@ struct GBAVideoGLRenderer { unsigned vramDirty; GLuint bgProgram[6]; + GLuint bgUniforms[6][GBA_GL_UNIFORM_MAX]; GLuint objProgram[2]; + GLuint objUniforms[2][GBA_GL_UNIFORM_MAX]; GLuint compositeProgram; + GLuint compositeUniforms[GBA_GL_UNIFORM_MAX]; GLuint finalizeProgram; + GLuint finalizeUniforms[GBA_GL_UNIFORM_MAX]; GBARegisterDISPCNT dispcnt; diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 80450afcd..33a523b20 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -43,6 +43,11 @@ static void _finalizeLayers(struct GBAVideoGLRenderer* renderer, int y); #define TEST_LAYER_ENABLED(X) !renderer->disableBG[X] && glRenderer->bg[X].enabled == 4 && glRenderer->bg[X].priority == priority +struct GBAVideoGLUniform { + const char* name; + int type; +}; + static const GLchar* const _gl3Header = "#version 130\n"; @@ -85,6 +90,19 @@ static const char* const _renderTile256 = " return color;\n" "}"; +const static struct GBAVideoGLUniform _uniformsMode0[] = { + { "loc", GBA_GL_VS_LOC, }, + { "maxPos", GBA_GL_VS_MAXPOS, }, + { "vram", GBA_GL_BG_VRAM, }, + { "palette", GBA_GL_BG_PALETTE, }, + { "screenBase", GBA_GL_BG_SCREENBASE, }, + { "charBase", GBA_GL_BG_CHARBASE, }, + { "size", GBA_GL_BG_SIZE, }, + { "offset", GBA_GL_BG_OFFSET, }, + { "inflags", GBA_GL_BG_INFLAGS, }, + { 0 } +}; + static const char* const _renderMode0 = "varying vec2 texCoord;\n" "uniform sampler2D vram;\n" @@ -137,6 +155,20 @@ static const char* const _fetchTileNoOverflow = " return renderTile(coord);\n" "}"; +const static struct GBAVideoGLUniform _uniformsMode2[] = { + { "loc", GBA_GL_VS_LOC, }, + { "maxPos", GBA_GL_VS_MAXPOS, }, + { "vram", GBA_GL_BG_VRAM, }, + { "palette", GBA_GL_BG_PALETTE, }, + { "screenBase", GBA_GL_BG_SCREENBASE, }, + { "charBase", GBA_GL_BG_CHARBASE, }, + { "size", GBA_GL_BG_SIZE, }, + { "inflags", GBA_GL_BG_INFLAGS, }, + { "offset", GBA_GL_BG_OFFSET, }, + { "transform", GBA_GL_BG_TRANSFORM, }, + { 0 } +}; + static const char* const _renderMode2 = "varying vec2 texCoord;\n" "uniform sampler2D vram;\n" @@ -189,6 +221,20 @@ static const char* const _renderMode2 = " flags = inflags / flagCoeff;\n" "}"; +const static struct GBAVideoGLUniform _uniformsObj[] = { + { "loc", GBA_GL_VS_LOC, }, + { "maxPos", GBA_GL_VS_MAXPOS, }, + { "vram", GBA_GL_OBJ_VRAM, }, + { "palette", GBA_GL_OBJ_PALETTE, }, + { "charBase", GBA_GL_OBJ_CHARBASE, }, + { "stride", GBA_GL_OBJ_STRIDE, }, + { "localPalette", GBA_GL_OBJ_LOCALPALETTE, }, + { "inflags", GBA_GL_OBJ_INFLAGS, }, + { "transform", GBA_GL_OBJ_TRANSFORM, }, + { "dims", GBA_GL_OBJ_DIMS, }, + { 0 } +}; + static const char* const _renderObj = "varying vec2 texCoord;\n" "uniform sampler2D vram;\n" @@ -214,6 +260,20 @@ static const char* const _renderObj = " flags = inflags / flagCoeff;\n" "}"; +const static struct GBAVideoGLUniform _uniformsComposite[] = { + { "loc", GBA_GL_VS_LOC, }, + { "maxPos", GBA_GL_VS_MAXPOS, }, + { "scale", GBA_GL_COMPOSITE_SCALE, }, + { "layerId", GBA_GL_COMPOSITE_LAYERID, }, + { "layer", GBA_GL_COMPOSITE_LAYER, }, + { "layerFlags", GBA_GL_COMPOSITE_LAYERFLAGS, }, + { "oldLayer", GBA_GL_COMPOSITE_OLDLAYER, }, + { "oldLayerFlags", GBA_GL_COMPOSITE_OLDLAYERFLAGS, }, + { "oldOldFlags", GBA_GL_COMPOSITE_OLDOLDFLAGS, }, + { "window", GBA_GL_COMPOSITE_WINDOW, }, + { 0 } +}; + static const char* const _composite = "varying vec2 texCoord;\n" "uniform int scale;\n" @@ -261,6 +321,17 @@ static const char* const _composite = " }\n" "}"; +const static struct GBAVideoGLUniform _uniformsFinalize[] = { + { "loc", GBA_GL_VS_LOC, }, + { "maxPos", GBA_GL_VS_MAXPOS, }, + { "scale", GBA_GL_FINALIZE_SCALE, }, + { "layer", GBA_GL_FINALIZE_LAYER, }, + { "layerFlags", GBA_GL_FINALIZE_LAYERFLAGS, }, + { "oldLayer", GBA_GL_FINALIZE_OLDLAYER, }, + { "oldFlags", GBA_GL_FINALIZE_OLDFLAGS, }, + { 0 } +}; + static const char* const _finalize = "varying vec2 texCoord;\n" "uniform int scale;\n" @@ -347,6 +418,13 @@ static void _initFramebufferTexture(GLuint tex, GLenum format, GLenum attachment glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex, 0); } +static void _lookupUniforms(GLuint program, GLuint* out, const struct GBAVideoGLUniform* uniforms) { + size_t i; + for (i = 0; uniforms[i].name; ++i) { + out[uniforms[i].type] = glGetUniformLocation(program, uniforms[i].name); + } +} + void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; glGenFramebuffers(GBA_GL_FBO_MAX, glRenderer->fbo); @@ -442,33 +520,41 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { shaderBuffer[2] = _renderTile16; _compileShader(glRenderer, glRenderer->bgProgram[0], shaderBuffer, 3, vs, log); + _lookupUniforms(glRenderer->bgProgram[0], glRenderer->bgUniforms[0], _uniformsMode0); shaderBuffer[2] = _renderTile256; _compileShader(glRenderer, glRenderer->bgProgram[1], shaderBuffer, 3, vs, log); + _lookupUniforms(glRenderer->bgProgram[1], glRenderer->bgUniforms[1], _uniformsMode0); shaderBuffer[1] = _renderMode2; shaderBuffer[2] = _fetchTileOverflow; _compileShader(glRenderer, glRenderer->bgProgram[2], shaderBuffer, 3, vs, log); + _lookupUniforms(glRenderer->bgProgram[2], glRenderer->bgUniforms[2], _uniformsMode2); shaderBuffer[2] = _fetchTileNoOverflow; _compileShader(glRenderer, glRenderer->bgProgram[3], shaderBuffer, 3, vs, log); + _lookupUniforms(glRenderer->bgProgram[3], glRenderer->bgUniforms[3], _uniformsMode2); shaderBuffer[1] = _renderObj; shaderBuffer[2] = _renderTile16; _compileShader(glRenderer, glRenderer->objProgram[0], shaderBuffer, 3, vs, log); + _lookupUniforms(glRenderer->objProgram[0], glRenderer->objUniforms[0], _uniformsObj); shaderBuffer[2] = _renderTile256; _compileShader(glRenderer, glRenderer->objProgram[1], shaderBuffer, 3, vs, log); + _lookupUniforms(glRenderer->objProgram[1], glRenderer->objUniforms[1], _uniformsObj); shaderBuffer[1] = _composite; _compileShader(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log); + _lookupUniforms(glRenderer->compositeProgram, glRenderer->compositeUniforms, _uniformsComposite); glBindFragDataLocation(glRenderer->compositeProgram, 2, "oldColor"); glBindFragDataLocation(glRenderer->compositeProgram, 3, "oldFlags"); shaderBuffer[1] = _finalize; _compileShader(glRenderer, glRenderer->finalizeProgram, shaderBuffer, 2, vs, log); + _lookupUniforms(glRenderer->finalizeProgram, glRenderer->finalizeUniforms, _uniformsFinalize); glDeleteShader(vs); @@ -963,6 +1049,7 @@ static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLu if ((y & 0x1F) != 0x1F) { return; } + const GLuint* uniforms = renderer->compositeUniforms; glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_COMPOSITE]); glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); glScissor(0, (y & ~0x1F) * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale); @@ -979,16 +1066,16 @@ static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLu glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_OLD_FLAGS]); glActiveTexture(GL_TEXTURE0 + 5); glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_WINDOW]); - glUniform2i(0, 0x20, y & ~0x1F); - glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); - glUniform1i(2, renderer->scale); - glUniform1i(3, 1 << id); - glUniform1i(4, 0); - glUniform1i(5, 1); - glUniform1i(6, 2); - glUniform1i(7, 3); - glUniform1i(8, 4); - glUniform1i(9, 5); + glUniform2i(uniforms[GBA_GL_VS_LOC], 0x20, y & ~0x1F); + glUniform2i(uniforms[GBA_GL_VS_MAXPOS], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); + glUniform1i(uniforms[GBA_GL_COMPOSITE_SCALE], renderer->scale); + glUniform1i(uniforms[GBA_GL_COMPOSITE_LAYERID], 1 << id); + glUniform1i(uniforms[GBA_GL_COMPOSITE_LAYER], 0); + glUniform1i(uniforms[GBA_GL_COMPOSITE_LAYERFLAGS], 1); + glUniform1i(uniforms[GBA_GL_COMPOSITE_OLDLAYER], 2); + glUniform1i(uniforms[GBA_GL_COMPOSITE_OLDLAYERFLAGS], 3); + glUniform1i(uniforms[GBA_GL_COMPOSITE_OLDOLDFLAGS], 4); + glUniform1i(uniforms[GBA_GL_COMPOSITE_WINDOW], 5); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawBuffers(4, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 }); @@ -1001,6 +1088,7 @@ void _finalizeLayers(struct GBAVideoGLRenderer* renderer, int y) { if ((y & 0x1F) != 0x1F) { return; } + const GLuint* uniforms = renderer->finalizeUniforms; glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OUTPUT]); glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); glScissor(0, (y & ~0x1F) * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale); @@ -1013,13 +1101,13 @@ void _finalizeLayers(struct GBAVideoGLRenderer* renderer, int y) { glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_OLD_COLOR]); glActiveTexture(GL_TEXTURE0 + 3); glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_OLD_FLAGS]); - glUniform2i(0, 0x20, y & ~0x1F); - glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); - glUniform1i(2, renderer->scale); - glUniform1i(3, 0); - glUniform1i(4, 1); - glUniform1i(5, 2); - glUniform1i(6, 3); + glUniform2i(uniforms[GBA_GL_VS_LOC], 0x20, y & ~0x1F); + glUniform2i(uniforms[GBA_GL_VS_MAXPOS], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); + glUniform1i(uniforms[GBA_GL_FINALIZE_SCALE], renderer->scale); + glUniform1i(uniforms[GBA_GL_FINALIZE_LAYER], 0); + glUniform1i(uniforms[GBA_GL_FINALIZE_LAYERFLAGS], 1); + glUniform1i(uniforms[GBA_GL_FINALIZE_OLDLAYER], 2); + glUniform1i(uniforms[GBA_GL_FINALIZE_OLDFLAGS], 3); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -1053,6 +1141,7 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB enum GBAVideoBlendEffect blendEffect = GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT ? BLEND_ALPHA : renderer->blendEffect; + const GLuint* uniforms = renderer->objUniforms[GBAObjAttributesAGet256Color(sprite->a)]; glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OBJ]); glViewport(x * renderer->scale, spriteY * renderer->scale, totalWidth * renderer->scale, totalHeight * renderer->scale); glScissor(x * renderer->scale, y * renderer->scale, totalWidth * renderer->scale, renderer->scale); @@ -1061,14 +1150,14 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB glBindTexture(GL_TEXTURE_2D, renderer->vramTex); glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, renderer->paletteTex); - glUniform2i(0, 1, y - spriteY); - glUniform2i(1, (GBAObjAttributesBIsHFlip(sprite->b) && !GBAObjAttributesAIsTransformed(sprite->a)) ? -totalWidth : totalWidth, totalHeight); - glUniform1i(2, 0); - glUniform1i(3, 1); - glUniform1i(4, charBase); - glUniform1i(5, stride); - glUniform1i(6, GBAObjAttributesCGetPalette(sprite->c)); - glUniform4i(7, GBAObjAttributesCGetPriority(sprite->c) << 3, + glUniform2i(uniforms[GBA_GL_VS_LOC], 1, y - spriteY); + glUniform2i(uniforms[GBA_GL_VS_MAXPOS], (GBAObjAttributesBIsHFlip(sprite->b) && !GBAObjAttributesAIsTransformed(sprite->a)) ? -totalWidth : totalWidth, totalHeight); + glUniform1i(uniforms[GBA_GL_OBJ_VRAM], 0); + glUniform1i(uniforms[GBA_GL_OBJ_PALETTE], 1); + glUniform1i(uniforms[GBA_GL_OBJ_CHARBASE], charBase); + glUniform1i(uniforms[GBA_GL_OBJ_STRIDE], stride); + glUniform1i(uniforms[GBA_GL_OBJ_LOCALPALETTE], GBAObjAttributesCGetPalette(sprite->c)); + glUniform4i(uniforms[GBA_GL_OBJ_INFLAGS], GBAObjAttributesCGetPriority(sprite->c) << 3, (renderer->target1Obj || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) | (renderer->target2Obj * 2) | (blendEffect * 4), blendEffect == BLEND_ALPHA ? renderer->blda : renderer->bldy, renderer->bldb); if (GBAObjAttributesAIsTransformed(sprite->a)) { @@ -1078,11 +1167,11 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB LOAD_16(mat.c, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].c); LOAD_16(mat.d, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].d); - glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { mat.a / 256.f, mat.c / 256.f, mat.b / 256.f, mat.d / 256.f }); + glUniformMatrix2fv(uniforms[GBA_GL_OBJ_TRANSFORM], 1, GL_FALSE, (GLfloat[]) { mat.a / 256.f, mat.c / 256.f, mat.b / 256.f, mat.d / 256.f }); } else { - glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { 1.f, 0, 0, 1.f }); + glUniformMatrix2fv(uniforms[GBA_GL_OBJ_TRANSFORM], 1, GL_FALSE, (GLfloat[]) { 1.f, 0, 0, 1.f }); } - glUniform4i(9, width, height, totalWidth, totalHeight); + glUniform4i(uniforms[GBA_GL_OBJ_DIMS], width, height, totalWidth, totalHeight); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); @@ -1098,6 +1187,7 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, } else if (background->size == 3) { yBase += (inY & 0x100) << 1; } + const GLuint* uniforms = renderer->bgUniforms[background->multipalette ? 1 : 0]; glBindFramebuffer(GL_FRAMEBUFFER, background->fbo); glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); glScissor(0, y * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale); @@ -1106,17 +1196,17 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, glBindTexture(GL_TEXTURE_2D, renderer->vramTex); glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, renderer->paletteTex); - glUniform2i(0, 1, y); - glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); - glUniform1i(2, 0); - glUniform1i(3, 1); - glUniform1i(4, background->screenBase); - glUniform1i(5, background->charBase); - glUniform1i(6, background->size); - glUniform2i(7, background->x, yBase - y); - glUniform4i(8, (background->priority << 3) + (background->index << 1) + 1, - background->target1 | (background->target2 * 2) | (renderer->blendEffect * 4), - renderer->blendEffect == BLEND_ALPHA ? renderer->blda : renderer->bldy, renderer->bldb); + glUniform2i(uniforms[GBA_GL_VS_LOC], 1, y); + glUniform2i(uniforms[GBA_GL_VS_MAXPOS], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); + glUniform1i(uniforms[GBA_GL_BG_VRAM], 0); + glUniform1i(uniforms[GBA_GL_BG_PALETTE], 1); + glUniform1i(uniforms[GBA_GL_BG_SCREENBASE], background->screenBase); + glUniform1i(uniforms[GBA_GL_BG_CHARBASE], background->charBase); + glUniform1i(uniforms[GBA_GL_BG_SIZE], background->size); + glUniform2i(uniforms[GBA_GL_BG_OFFSET], background->x, yBase - y); + glUniform4i(uniforms[GBA_GL_BG_INFLAGS], (background->priority << 3) + (background->index << 1) + 1, + background->target1 | (background->target2 * 2) | (renderer->blendEffect * 4), + renderer->blendEffect == BLEND_ALPHA ? renderer->blda : renderer->bldy, renderer->bldb); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); @@ -1127,6 +1217,7 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, } void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { + const GLuint* uniforms = renderer->bgUniforms[background->overflow ? 2 : 3]; glBindFramebuffer(GL_FRAMEBUFFER, background->fbo); glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); glScissor(0, y * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale); @@ -1135,37 +1226,37 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, glBindTexture(GL_TEXTURE_2D, renderer->vramTex); glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, renderer->paletteTex); - glUniform2i(0, 1, y); - glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); - glUniform1i(2, 0); - glUniform1i(3, 1); - glUniform1i(4, background->screenBase); - glUniform1i(5, background->charBase); - glUniform1i(6, background->size); - glUniform4i(7, (background->priority << 3) + (background->index << 1) + 1, + glUniform2i(uniforms[GBA_GL_VS_LOC], 1, y); + glUniform2i(uniforms[GBA_GL_VS_MAXPOS], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); + glUniform1i(uniforms[GBA_GL_BG_VRAM], 0); + glUniform1i(uniforms[GBA_GL_BG_PALETTE], 1); + glUniform1i(uniforms[GBA_GL_BG_SCREENBASE], background->screenBase); + glUniform1i(uniforms[GBA_GL_BG_CHARBASE], background->charBase); + glUniform1i(uniforms[GBA_GL_BG_SIZE], background->size); + glUniform4i(uniforms[GBA_GL_BG_INFLAGS], (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2) | (renderer->blendEffect * 4), renderer->blendEffect == BLEND_ALPHA ? renderer->blda : renderer->bldy, renderer->bldb); if (renderer->scale > 1) { - glUniform2iv(8, 4, (GLint[]) { + glUniform2iv(uniforms[GBA_GL_BG_OFFSET], 4, (GLint[]) { background->affine[0].sx, background->affine[0].sy, background->affine[1].sx, background->affine[1].sy, background->affine[2].sx, background->affine[2].sy, background->affine[3].sx, background->affine[3].sy, }); - glUniform2iv(12, 4, (GLint[]) { + glUniform2iv(uniforms[GBA_GL_BG_TRANSFORM], 4, (GLint[]) { background->affine[0].dx, background->affine[0].dy, background->affine[1].dx, background->affine[1].dy, background->affine[2].dx, background->affine[2].dy, background->affine[3].dx, background->affine[3].dy, }); } else { - glUniform2iv(8, 4, (GLint[]) { + glUniform2iv(uniforms[GBA_GL_BG_OFFSET], 4, (GLint[]) { background->affine[0].sx, background->affine[0].sy, background->affine[0].sx, background->affine[0].sy, background->affine[0].sx, background->affine[0].sy, background->affine[0].sx, background->affine[0].sy, }); - glUniform2iv(12, 4, (GLint[]) { + glUniform2iv(uniforms[GBA_GL_BG_TRANSFORM], 4, (GLint[]) { background->affine[0].dx, background->affine[0].dy, background->affine[0].dx, background->affine[0].dy, background->affine[0].dx, background->affine[0].dy, From 2752c98b17a2d0e4fdb6a1b2a456bf5bb2968aa5 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 14 May 2019 09:54:54 -0700 Subject: [PATCH 26/44] GBA Video: GL compatibility fixes --- src/gba/renderers/gl.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 33a523b20..d266417ab 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -52,10 +52,10 @@ static const GLchar* const _gl3Header = "#version 130\n"; static const char* const _vertexShader = - "attribute vec2 position;\n" + "in vec2 position;\n" "uniform ivec2 loc;\n" "uniform ivec2 maxPos;\n" - "varying vec2 texCoord;\n" + "out vec2 texCoord;\n" "void main() {\n" " vec2 local = vec2(position.x, float(position.y * loc.x + loc.y) / abs(maxPos.y));\n" @@ -104,7 +104,7 @@ const static struct GBAVideoGLUniform _uniformsMode0[] = { }; static const char* const _renderMode0 = - "varying vec2 texCoord;\n" + "in vec2 texCoord;\n" "uniform sampler2D vram;\n" "uniform sampler2D palette;\n" "uniform int screenBase;\n" @@ -170,7 +170,7 @@ const static struct GBAVideoGLUniform _uniformsMode2[] = { }; static const char* const _renderMode2 = - "varying vec2 texCoord;\n" + "in vec2 texCoord;\n" "uniform sampler2D vram;\n" "uniform sampler2D palette;\n" "uniform int screenBase;\n" @@ -236,7 +236,7 @@ const static struct GBAVideoGLUniform _uniformsObj[] = { }; static const char* const _renderObj = - "varying vec2 texCoord;\n" + "in vec2 texCoord;\n" "uniform sampler2D vram;\n" "uniform sampler2D palette;\n" "uniform int charBase;\n" @@ -275,7 +275,7 @@ const static struct GBAVideoGLUniform _uniformsComposite[] = { }; static const char* const _composite = - "varying vec2 texCoord;\n" + "in vec2 texCoord;\n" "uniform int scale;\n" "uniform int layerId\n;" "uniform sampler2D layer;\n" @@ -333,13 +333,14 @@ const static struct GBAVideoGLUniform _uniformsFinalize[] = { }; static const char* const _finalize = - "varying vec2 texCoord;\n" + "in vec2 texCoord;\n" "uniform int scale;\n" "uniform sampler2D layer;\n" "uniform sampler2D layerFlags;\n" "uniform sampler2D oldLayer;\n" "uniform sampler2D oldFlags;\n" "const vec4 flagCoeff = vec4(32., 32., 16., 16.);\n" + "out vec4 color;\n" "void main() {\n" " vec4 pix = texelFetch(layer, ivec2(texCoord * scale), 0);\n" @@ -356,7 +357,7 @@ static const char* const _finalize = " } else if ((inflags.y & 13) == 13) {\n" " pix -= pix * inflags.z / 16.;\n" " }\n" - " gl_FragColor = pix;\n" + " color = pix;\n" "}"; static const GLint _vertices[] = { From 49a9da3e5ca5e414d58a2f15920d1349c01124c4 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 14 May 2019 10:23:09 -0700 Subject: [PATCH 27/44] GBA Video: GL OBJWIN --- include/mgba/internal/gba/renderers/gl.h | 1 + src/gba/renderers/gl.c | 23 +++++++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index c5a09f24a..435c13c71 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -103,6 +103,7 @@ enum { GBA_GL_OBJ_INFLAGS, GBA_GL_OBJ_TRANSFORM, GBA_GL_OBJ_DIMS, + GBA_GL_OBJ_OBJWIN, GBA_GL_COMPOSITE_SCALE = 2, GBA_GL_COMPOSITE_LAYERID, diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index d266417ab..ca133d81b 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -232,6 +232,7 @@ const static struct GBAVideoGLUniform _uniformsObj[] = { { "inflags", GBA_GL_OBJ_INFLAGS, }, { "transform", GBA_GL_OBJ_TRANSFORM, }, { "dims", GBA_GL_OBJ_DIMS, }, + { "objwin", GBA_GL_OBJ_OBJWIN, }, { 0 } }; @@ -245,8 +246,10 @@ static const char* const _renderObj = "uniform ivec4 inflags;\n" "uniform mat2x2 transform;\n" "uniform ivec4 dims;\n" + "uniform vec3 objwin;\n" "out vec4 color;\n" "out vec4 flags;\n" + "out vec2 window;\n" "const vec4 flagCoeff = vec4(32., 32., 16., 16.);\n" "vec4 renderTile(int tile, int paletteId, ivec2 localCoord);\n" @@ -256,8 +259,13 @@ static const char* const _renderObj = " if ((coord & ~(dims.xy - 1)) != ivec2(0, 0)) {\n" " discard;\n" " }\n" - " color = renderTile((coord.x >> 3) + (coord.y >> 3) * stride, 16 + localPalette, coord & 7);\n" + " vec4 pix = renderTile((coord.x >> 3) + (coord.y >> 3) * stride, 16 + localPalette, coord & 7);\n" + " if (objwin.x > 0) {\n" + " pix.a = 0;\n" + " }\n" + " color = pix;\n" " flags = inflags / flagCoeff;\n" + " window = objwin.yz;\n" "}"; const static struct GBAVideoGLUniform _uniformsComposite[] = { @@ -542,10 +550,12 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { shaderBuffer[2] = _renderTile16; _compileShader(glRenderer, glRenderer->objProgram[0], shaderBuffer, 3, vs, log); _lookupUniforms(glRenderer->objProgram[0], glRenderer->objUniforms[0], _uniformsObj); + glBindFragDataLocation(glRenderer->objProgram[0], 2, "window"); shaderBuffer[2] = _renderTile256; _compileShader(glRenderer, glRenderer->objProgram[1], shaderBuffer, 3, vs, log); _lookupUniforms(glRenderer->objProgram[1], glRenderer->objUniforms[1], _uniformsObj); + glBindFragDataLocation(glRenderer->objProgram[1], 2, "window"); shaderBuffer[1] = _composite; _compileShader(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log); @@ -879,7 +889,6 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { glRenderer->firstAffine = -1; } - int spriteLayers = 0; if (GBARegisterDISPCNTIsObjEnable(glRenderer->dispcnt) && !glRenderer->d.disableOBJ) { if (glRenderer->oamDirty) { glRenderer->oamMax = GBAVideoRendererCleanOAM(glRenderer->d.oam->obj, glRenderer->sprites, 0); @@ -893,7 +902,6 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } GBAVideoGLRendererDrawSprite(glRenderer, &sprite->obj, y, sprite->y); - spriteLayers |= 1 << GBAObjAttributesCGetPriority(sprite->obj.c); } } @@ -1175,7 +1183,14 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB glUniform4i(uniforms[GBA_GL_OBJ_DIMS], width, height, totalWidth, totalHeight); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); - glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); + if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_OBJWIN) { + int window = ~renderer->objwin & 0xFF; + glUniform3f(uniforms[GBA_GL_OBJ_OBJWIN], 1, (window & 0xF) / 32.f, (window >> 4) / 32.f); + glDrawBuffers(3, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }); + } else { + glUniform3f(uniforms[GBA_GL_OBJ_OBJWIN], 0, 0, 0); + glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); + } glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); } From 8450417086c5b70904f93f2db720456d54c9cfeb Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 14 May 2019 13:02:36 -0700 Subject: [PATCH 28/44] Core: Improve OpenGL integration, update Qt to use improvements --- CMakeLists.txt | 22 +++++++-- include/mgba/core/core.h | 1 + include/mgba/core/interface.h | 4 ++ include/mgba/internal/gba/renderers/gl.h | 9 +++- src/gb/core.c | 9 ++++ src/gba/core.c | 39 ++++++++++++++- src/gba/renderers/gl.c | 49 +++++++++++++------ src/platform/qt/CMakeLists.txt | 15 +----- src/platform/qt/CoreController.cpp | 60 +++++++++++++++-------- src/platform/qt/CoreController.h | 9 ++++ src/platform/qt/Display.h | 1 + src/platform/qt/DisplayGL.cpp | 61 +++++++++++++++++------- src/platform/qt/DisplayGL.h | 3 ++ src/platform/qt/Window.cpp | 15 +++++- src/platform/sdl/CMakeLists.txt | 5 +- src/platform/sdl/gles2-sdl.c | 4 +- tools/sanitize-deb.sh | 2 + 17 files changed, 228 insertions(+), 80 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 63171dfd4..7b497822d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,7 @@ if(NOT LIBMGBA_ONLY) set(BUILD_SHARED ON CACHE BOOL "Build a shared library") set(SKIP_LIBRARY OFF CACHE BOOL "Skip building the library (useful for only building libretro or OpenEmu cores)") set(BUILD_GL ON CACHE BOOL "Build with OpenGL") - set(BUILD_GLES2 OFF CACHE BOOL "Build with OpenGL|ES 2") + set(BUILD_GLES2 ON CACHE BOOL "Build with OpenGL|ES 2") set(BUILD_GLES3 OFF CACHE BOOL "Build with OpenGL|ES 3") set(USE_EPOXY ON CACHE STRING "Build with libepoxy") set(DISABLE_DEPS OFF CACHE BOOL "Build without dependencies") @@ -447,7 +447,7 @@ set(FEATURE_DEFINES) set(FEATURE_FLAGS) set(FEATURES) set(ENABLES) -if(CMAKE_SYSTEM_NAME MATCHES .*BSD) +if(CMAKE_SYSTEM_NAME MATCHES ".*BSD|DragonFly") set(LIBEDIT_LIBRARIES -ledit) if (CMAKE_SYSTEM_NAME STREQUAL OpenBSD) list(APPEND LIBEDIT_LIBRARIES -ltermcap) @@ -462,9 +462,9 @@ if(BUILD_GL) endif() endif() if(NOT BUILD_GL) - set(OPENGLE_LIBRARY "" CACHE PATH "" FORCE) + set(OPENGL_LIBRARY "" CACHE PATH "" FORCE) endif() -if(BUILD_GLES2 AND NOT BUILD_RASPI) +if(BUILD_GLES2 AND NOT BUILD_RASPI AND NOT CMAKE_SYSTEM_NAME MATCHES "^(Windows|Darwin|Linux|.*BSD|DragonFly|Haiku)$") find_path(OPENGLES2_INCLUDE_DIR NAMES GLES2/gl2.h) find_library(OPENGLES2_LIBRARY NAMES GLESv2 GLESv2_CM) if(NOT OPENGLES2_INCLUDE_DIR OR NOT OPENGLES2_LIBRARY) @@ -474,6 +474,16 @@ endif() if(NOT BUILD_GLES2) set(OPENGLES2_LIBRARY "" CACHE PATH "" FORCE) endif() +if(BUILD_GL) + list(APPEND OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gl.c) + list(APPEND OS_LIB ${OPENGL_LIBRARY}) + include_directories(${OPENGL_INCLUDE_DIR}) +endif() +if(BUILD_GLES2) + list(APPEND OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gles2.c) + list(APPEND OS_LIB ${OPENGLES2_LIBRARY}) + include_directories(${OPENGLES2_INCLUDE_DIR}) +endif() if(BUILD_GLES3) find_path(OPENGLES3_INCLUDE_DIR NAMES GLES3/gl3.h) find_library(OPENGLES3_LIBRARY NAMES GLESv3 GLESv2) @@ -733,6 +743,10 @@ if(USE_EPOXY) link_directories(${EPOXY_LIBRARY_DIRS}) set(OPENGLES2_LIBRARY ${EPOXY_LIBRARIES}) set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libepoxy0") +elseif(BUILD_GL) + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libgl1|libgles2") +elseif(BUILD_GLES2) + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libgles2") endif() if(USE_SQLITE3) diff --git a/include/mgba/core/core.h b/include/mgba/core/core.h index 124b02411..9cad7a3e8 100644 --- a/include/mgba/core/core.h +++ b/include/mgba/core/core.h @@ -64,6 +64,7 @@ struct mCore { void (*deinit)(struct mCore*); enum mPlatform (*platform)(const struct mCore*); + bool (*supportsFeature)(const struct mCore*, enum mCoreFeature); void (*setSync)(struct mCore*, struct mCoreSync*); void (*loadConfig)(struct mCore*, const struct mCoreConfig*); diff --git a/include/mgba/core/interface.h b/include/mgba/core/interface.h index 2e9ff63a7..51ba6447f 100644 --- a/include/mgba/core/interface.h +++ b/include/mgba/core/interface.h @@ -80,6 +80,10 @@ enum mColorFormat { mCOLOR_ANY = -1 }; +enum mCoreFeature { + mCORE_FEATURE_OPENGL = 1, +}; + struct mCoreCallbacks { void* context; void (*videoFrameStarted)(void* context); diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index 435c13c71..6ac96a50e 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -16,6 +16,8 @@ CXX_GUARD_START #include #include +#if defined(BUILD_GLES2) || defined(BUILD_GLES3) + #ifdef USE_EPOXY #include #elif defined(BUILD_GL) @@ -27,7 +29,7 @@ CXX_GUARD_START #include #endif #else -#include +#include #endif struct GBAVideoGLAffine { @@ -137,6 +139,9 @@ struct GBAVideoGLRenderer { GLuint outputTex; +#ifdef BUILD_GLES3 + uint16_t shadowPalette[512]; +#endif GLuint paletteTex; bool paletteDirty; @@ -182,6 +187,8 @@ struct GBAVideoGLRenderer { void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer); +#endif + CXX_GUARD_END #endif \ No newline at end of file diff --git a/src/gb/core.c b/src/gb/core.c index 20e383393..264f29bf1 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -138,6 +138,14 @@ static enum mPlatform _GBCorePlatform(const struct mCore* core) { return PLATFORM_GB; } +static bool _GBCoreSupportsFeature(const struct mCore* core, enum mCoreFeature feature) { + UNUSED(core); + switch (feature) { + default: + return false; + } +} + static void _GBCoreSetSync(struct mCore* core, struct mCoreSync* sync) { struct GB* gb = core->board; gb->sync = sync; @@ -888,6 +896,7 @@ struct mCore* GBCoreCreate(void) { core->init = _GBCoreInit; core->deinit = _GBCoreDeinit; core->platform = _GBCorePlatform; + core->supportsFeature = _GBCoreSupportsFeature; core->setSync = _GBCoreSetSync; core->loadConfig = _GBCoreLoadConfig; core->desiredVideoDimensions = _GBCoreDesiredVideoDimensions; diff --git a/src/gba/core.c b/src/gba/core.c index 5284a04b9..839404d03 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -17,7 +17,9 @@ #ifndef DISABLE_THREADING #include #endif +#ifdef BUILD_GLES2 #include +#endif #include #include #include @@ -124,7 +126,9 @@ struct mVideoLogContext; struct GBACore { struct mCore d; struct GBAVideoSoftwareRenderer renderer; +#ifdef BUILD_GLES2 struct GBAVideoGLRenderer glRenderer; +#endif struct GBAVideoProxyRenderer proxyRenderer; struct mVideoLogContext* logContext; struct mCoreCallbacks logCallbacks; @@ -170,8 +174,10 @@ static bool _GBACoreInit(struct mCore* core) { GBAVideoSoftwareRendererCreate(&gbacore->renderer); gbacore->renderer.outputBuffer = NULL; +#ifdef BUILD_GLES2 GBAVideoGLRendererCreate(&gbacore->glRenderer); gbacore->glRenderer.outputTex = -1; +#endif #ifndef DISABLE_THREADING mVideoThreadProxyCreate(&gbacore->threadProxy); @@ -212,6 +218,20 @@ static enum mPlatform _GBACorePlatform(const struct mCore* core) { return PLATFORM_GBA; } +static bool _GBACoreSupportsFeature(const struct mCore* core, enum mCoreFeature feature) { + UNUSED(core); + switch (feature) { + case mCORE_FEATURE_OPENGL: +#ifdef BUILD_GLES2 + return true; +#else + return false; +#endif + default: + return false; + } +} + static void _GBACoreSetSync(struct mCore* core, struct mCoreSync* sync) { struct GBA* gba = core->board; gba->sync = sync; @@ -261,9 +281,12 @@ static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* con } static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) { +#ifdef BUILD_GLES2 struct GBACore* gbacore = (struct GBACore*) core; - int fakeBool; int scale = gbacore->glRenderer.scale; +#else + int scale = 1; +#endif *width = GBA_VIDEO_HORIZONTAL_PIXELS * scale; *height = GBA_VIDEO_VERTICAL_PIXELS * scale; @@ -277,8 +300,13 @@ static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t s } static void _GBACoreSetVideoGLTex(struct mCore* core, unsigned texid) { +#ifdef BUILD_GLES2 struct GBACore* gbacore = (struct GBACore*) core; gbacore->glRenderer.outputTex = texid; +#else + UNUSED(core); + UNUSED(texid); +#endif } static void _GBACoreGetPixels(struct mCore* core, const void** buffer, size_t* stride) { @@ -403,16 +431,22 @@ static void _GBACoreChecksum(const struct mCore* core, void* data, enum mCoreChe static void _GBACoreReset(struct mCore* core) { struct GBACore* gbacore = (struct GBACore*) core; struct GBA* gba = (struct GBA*) core->board; - if (gbacore->renderer.outputBuffer || gbacore->glRenderer.outputTex != (unsigned) -1) { + if (gbacore->renderer.outputBuffer +#ifdef BUILD_GLES2 + || gbacore->glRenderer.outputTex != (unsigned) -1 +#endif + ) { struct GBAVideoRenderer* renderer; if (gbacore->renderer.outputBuffer) { renderer = &gbacore->renderer.d; } int fakeBool; +#ifdef BUILD_GLES2 if (gbacore->glRenderer.outputTex != (unsigned) -1 && mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) { renderer = &gbacore->glRenderer.d; mCoreConfigGetIntValue(&core->config, "videoScale", &gbacore->glRenderer.scale); } +#endif #ifndef DISABLE_THREADING if (mCoreConfigGetIntValue(&core->config, "threadedVideo", &fakeBool) && fakeBool) { if (!core->videoLogger) { @@ -952,6 +986,7 @@ struct mCore* GBACoreCreate(void) { core->init = _GBACoreInit; core->deinit = _GBACoreDeinit; core->platform = _GBACorePlatform; + core->supportsFeature = _GBACoreSupportsFeature; core->setSync = _GBACoreSetSync; core->loadConfig = _GBACoreLoadConfig; core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions; diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index ca133d81b..bdd065cb8 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -5,6 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#if defined(BUILD_GLES2) || defined(BUILD_GLES3) + #include #include #include @@ -90,7 +92,7 @@ static const char* const _renderTile256 = " return color;\n" "}"; -const static struct GBAVideoGLUniform _uniformsMode0[] = { +static const struct GBAVideoGLUniform _uniformsMode0[] = { { "loc", GBA_GL_VS_LOC, }, { "maxPos", GBA_GL_VS_MAXPOS, }, { "vram", GBA_GL_BG_VRAM, }, @@ -155,7 +157,7 @@ static const char* const _fetchTileNoOverflow = " return renderTile(coord);\n" "}"; -const static struct GBAVideoGLUniform _uniformsMode2[] = { +static const struct GBAVideoGLUniform _uniformsMode2[] = { { "loc", GBA_GL_VS_LOC, }, { "maxPos", GBA_GL_VS_MAXPOS, }, { "vram", GBA_GL_BG_VRAM, }, @@ -221,7 +223,7 @@ static const char* const _renderMode2 = " flags = inflags / flagCoeff;\n" "}"; -const static struct GBAVideoGLUniform _uniformsObj[] = { +static const struct GBAVideoGLUniform _uniformsObj[] = { { "loc", GBA_GL_VS_LOC, }, { "maxPos", GBA_GL_VS_MAXPOS, }, { "vram", GBA_GL_OBJ_VRAM, }, @@ -268,7 +270,7 @@ static const char* const _renderObj = " window = objwin.yz;\n" "}"; -const static struct GBAVideoGLUniform _uniformsComposite[] = { +static const struct GBAVideoGLUniform _uniformsComposite[] = { { "loc", GBA_GL_VS_LOC, }, { "maxPos", GBA_GL_VS_MAXPOS, }, { "scale", GBA_GL_COMPOSITE_SCALE, }, @@ -329,7 +331,7 @@ static const char* const _composite = " }\n" "}"; -const static struct GBAVideoGLUniform _uniformsFinalize[] = { +static const struct GBAVideoGLUniform _uniformsFinalize[] = { { "loc", GBA_GL_VS_LOC, }, { "maxPos", GBA_GL_VS_MAXPOS, }, { "scale", GBA_GL_FINALIZE_SCALE, }, @@ -413,8 +415,10 @@ void _compileShader(struct GBAVideoGLRenderer* glRenderer, GLuint program, const mLOG(GBA_VIDEO, ERROR, "Program link failure: %s", log); } glDeleteShader(fs); +#ifndef BUILD_GLES3 glBindFragDataLocation(program, 0, "color"); glBindFragDataLocation(program, 1, "flags"); +#endif } static void _initFramebufferTexture(GLuint tex, GLenum format, GLenum attachment, int scale) { @@ -550,18 +554,24 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { shaderBuffer[2] = _renderTile16; _compileShader(glRenderer, glRenderer->objProgram[0], shaderBuffer, 3, vs, log); _lookupUniforms(glRenderer->objProgram[0], glRenderer->objUniforms[0], _uniformsObj); +#ifndef BUILD_GLES3 glBindFragDataLocation(glRenderer->objProgram[0], 2, "window"); +#endif shaderBuffer[2] = _renderTile256; _compileShader(glRenderer, glRenderer->objProgram[1], shaderBuffer, 3, vs, log); _lookupUniforms(glRenderer->objProgram[1], glRenderer->objUniforms[1], _uniformsObj); +#ifndef BUILD_GLES3 glBindFragDataLocation(glRenderer->objProgram[1], 2, "window"); +#endif shaderBuffer[1] = _composite; _compileShader(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log); _lookupUniforms(glRenderer->compositeProgram, glRenderer->compositeUniforms, _uniformsComposite); +#ifndef BUILD_GLES3 glBindFragDataLocation(glRenderer->compositeProgram, 2, "oldColor"); glBindFragDataLocation(glRenderer->compositeProgram, 3, "oldFlags"); +#endif shaderBuffer[1] = _finalize; _compileShader(glRenderer, glRenderer->finalizeProgram, shaderBuffer, 2, vs, log); @@ -585,7 +595,6 @@ void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { glDeleteProgram(glRenderer->bgProgram[3]); glDeleteProgram(glRenderer->bgProgram[4]); glDeleteProgram(glRenderer->bgProgram[5]); - glDeleteProgram(glRenderer->bgProgram[6]); glDeleteProgram(glRenderer->objProgram[0]); glDeleteProgram(glRenderer->objProgram[1]); glDeleteProgram(glRenderer->compositeProgram); @@ -611,9 +620,13 @@ void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) } void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) { + struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; +#ifdef BUILD_GLES3 + glRenderer->shadowPalette[address >> 1] = (value & 0x3F) | ((value & 0x7FE0) << 1); +#else UNUSED(address); UNUSED(value); - struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; +#endif glRenderer->paletteDirty = true; } @@ -822,7 +835,11 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; if (glRenderer->paletteDirty) { glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex); +#ifdef BUILD_GLES3 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, 16, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_6_5, glRenderer->shadowPalette); +#else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 16, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, glRenderer->d.palette); +#endif glRenderer->paletteDirty = false; } int i; @@ -841,33 +858,33 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]); glEnable(GL_SCISSOR_TEST); glScissor(0, y * glRenderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, glRenderer->scale); - glDrawBuffer(GL_COLOR_ATTACHMENT0); + glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); glClear(GL_COLOR_BUFFER_BIT); if (y == 0) { glDisable(GL_SCISSOR_TEST); - glDrawBuffer(GL_COLOR_ATTACHMENT1); + glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT1 }); glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2) | (glRenderer->blendEffect * 4)) / 32.f, (glRenderer->blendEffect == BLEND_ALPHA ? glRenderer->blda : glRenderer->bldy) / 16.f, glRenderer->bldb / 16.f); glClear(GL_COLOR_BUFFER_BIT); glClearColor(0, 0, 0, 0); - glDrawBuffer(GL_COLOR_ATTACHMENT3); + glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT3 }); glClear(GL_COLOR_BUFFER_BIT); glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]); - glDrawBuffer(GL_COLOR_ATTACHMENT0); + glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); glClear(GL_COLOR_BUFFER_BIT); - glDrawBuffer(GL_COLOR_ATTACHMENT1); + glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT1 }); glClear(GL_COLOR_BUFFER_BIT); for (i = 0; i < 4; ++i) { glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo); - glDrawBuffer(GL_COLOR_ATTACHMENT0); + glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); glClear(GL_COLOR_BUFFER_BIT); - glDrawBuffer(GL_COLOR_ATTACHMENT1); + glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT1 }); glClear(GL_COLOR_BUFFER_BIT); } - glDrawBuffer(GL_COLOR_ATTACHMENT0); + glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); glEnable(GL_SCISSOR_TEST); } glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -1310,3 +1327,5 @@ void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y) { } glBindFramebuffer(GL_FRAMEBUFFER, 0); } + +#endif diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index 9b3eb63f0..98a0a9e5a 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -47,17 +47,6 @@ if(APPLE) endif() endif() -if(BUILD_GL) - list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c) - if(NOT WIN32 OR USE_EPOXY) - list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c) - endif() -endif() - -if(BUILD_GLES2) - list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c) -endif() - get_target_property(QT_TYPE Qt5::Core TYPE) if(QT_TYPE STREQUAL STATIC_LIBRARY) set(QT_STATIC ON) @@ -245,7 +234,7 @@ if(NOT DEFINED DATADIR) set(DATADIR ${CMAKE_INSTALL_DATADIR}/${BINARY_NAME}) endif() endif() -if(BUILD_GL OR BUILD_GLES2) +if(BUILD_GL OR BUILD_GLES2 OR BUILD_EPOXY) install(DIRECTORY ${CMAKE_SOURCE_DIR}/res/shaders DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt) endif() install(FILES ${CMAKE_SOURCE_DIR}/res/nointro.dat DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt) @@ -291,7 +280,7 @@ add_executable(${BINARY_NAME}-qt WIN32 MACOSX_BUNDLE main.cpp ${CMAKE_SOURCE_DIR set_target_properties(${BINARY_NAME}-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/res/info.plist.in COMPILE_DEFINITIONS "${FEATURE_DEFINES};${FUNCTION_DEFINES};${OS_DEFINES};${QT_DEFINES}" COMPILE_OPTIONS "${FEATURE_FLAGS}") list(APPEND QT_LIBRARIES Qt5::Widgets) -if(BUILD_GL OR BUILD_GLES2) +if(BUILD_GL OR BUILD_GLES2 OR BUILD_EPOXY) list(APPEND QT_LIBRARIES Qt5::OpenGL ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY}) endif() if(QT_STATIC) diff --git a/src/platform/qt/CoreController.cpp b/src/platform/qt/CoreController.cpp index 37ea45cac..2c6ec39f7 100644 --- a/src/platform/qt/CoreController.cpp +++ b/src/platform/qt/CoreController.cpp @@ -40,16 +40,6 @@ CoreController::CoreController(mCore* core, QObject* parent) m_threadContext.core = core; m_threadContext.userData = this; - QSize size(1024, 2048); - m_buffers[0].resize(size.width() * size.height() * sizeof(color_t)); - m_buffers[1].resize(size.width() * size.height() * sizeof(color_t)); - m_buffers[0].fill(0xFF); - m_buffers[1].fill(0xFF); - m_activeBuffer = &m_buffers[0]; - m_completeBuffer = m_buffers[0]; - - m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast(m_activeBuffer->data()), size.width()); - m_resetActions.append([this]() { if (m_autoload) { mCoreLoadState(m_threadContext.core, 0, m_loadStateFlags); @@ -91,8 +81,10 @@ CoreController::CoreController(mCore* core, QObject* parent) controller->m_resetActions.clear(); - controller->m_activeBuffer = &controller->m_buffers[0]; - context->core->setVideoBuffer(context->core, reinterpret_cast(controller->m_activeBuffer->data()), controller->screenDimensions().width()); + if (!controller->m_hwaccel) { + controller->m_activeBuffer = &controller->m_buffers[0]; + context->core->setVideoBuffer(context->core, reinterpret_cast(controller->m_activeBuffer->data()), controller->screenDimensions().width()); + } controller->finishFrame(); }; @@ -211,6 +203,9 @@ CoreController::~CoreController() { const color_t* CoreController::drawContext() { QMutexLocker locker(&m_mutex); + if (m_hwaccel) { + return nullptr; + } return reinterpret_cast(m_completeBuffer.constData()); } @@ -340,6 +335,18 @@ void CoreController::setLogger(LogController* logger) { } void CoreController::start() { + if (!m_hwaccel) { + QSize size(1024, 2048); + m_buffers[0].resize(size.width() * size.height() * sizeof(color_t)); + m_buffers[1].resize(size.width() * size.height() * sizeof(color_t)); + m_buffers[0].fill(0xFF); + m_buffers[1].fill(0xFF); + m_activeBuffer = &m_buffers[0]; + m_completeBuffer = m_buffers[0]; + + m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast(m_activeBuffer->data()), size.width()); + } + if (!m_patched) { mCoreAutoloadPatch(m_threadContext.core); } @@ -800,6 +807,16 @@ void CoreController::endVideoLog() { m_vl = nullptr; } +void CoreController::setFramebufferHandle(int fb) { + Interrupter interrupter(this); + if (fb < 0) { + m_hwaccel = false; + } else { + m_threadContext.core->setVideoGLTex(m_threadContext.core, fb); + m_hwaccel = true; + } +} + void CoreController::updateKeys() { int activeKeys = m_activeKeys | updateAutofire() | m_inputController->pollEvents(); m_threadContext.core->setKeys(m_threadContext.core, activeKeys); @@ -823,17 +840,18 @@ int CoreController::updateAutofire() { void CoreController::finishFrame() { QMutexLocker locker(&m_mutex); - memcpy(m_completeBuffer.data(), m_activeBuffer->constData(), m_activeBuffer->size()); + if (!m_hwaccel) { + memcpy(m_completeBuffer.data(), m_activeBuffer->constData(), m_activeBuffer->size()); - // TODO: Generalize this to triple buffering? - m_activeBuffer = &m_buffers[0]; - if (m_activeBuffer == m_completeBuffer) { - m_activeBuffer = &m_buffers[1]; + // TODO: Generalize this to triple buffering? + m_activeBuffer = &m_buffers[0]; + if (m_activeBuffer == m_completeBuffer) { + m_activeBuffer = &m_buffers[1]; + } + // Copy contents to avoid issues when doing frameskip + memcpy(m_activeBuffer->data(), m_completeBuffer.constData(), m_activeBuffer->size()); + m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast(m_activeBuffer->data()), screenDimensions().width()); } - // Copy contents to avoid issues when doing frameskip - memcpy(m_activeBuffer->data(), m_completeBuffer.constData(), m_activeBuffer->size()); - m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast(m_activeBuffer->data()), screenDimensions().width()); - for (auto& action : m_frameActions) { action(); } diff --git a/src/platform/qt/CoreController.h b/src/platform/qt/CoreController.h index dbcec9cf3..e31602117 100644 --- a/src/platform/qt/CoreController.h +++ b/src/platform/qt/CoreController.h @@ -46,6 +46,10 @@ public: static const bool VIDEO_SYNC = false; static const bool AUDIO_SYNC = true; + enum class Feature { + OPENGL = mCORE_FEATURE_OPENGL, + }; + class Interrupter { public: Interrupter(CoreController*, bool fromThread = false); @@ -69,6 +73,8 @@ public: mPlatform platform() const; QSize screenDimensions() const; + bool supportsFeature(Feature feature) const { return m_threadContext.core->supportsFeature(m_threadContext.core, static_cast(feature)); } + bool hardwareAccelerated() const { return m_hwaccel; } void loadConfig(ConfigController*); @@ -154,6 +160,8 @@ public slots: void startVideoLog(const QString& path); void endVideoLog(); + void setFramebufferHandle(int fb); + signals: void started(); void paused(); @@ -188,6 +196,7 @@ private: QByteArray m_buffers[2]; QByteArray* m_activeBuffer; QByteArray m_completeBuffer; + bool m_hwaccel = false; std::unique_ptr m_cacheSet; std::unique_ptr m_override; diff --git a/src/platform/qt/Display.h b/src/platform/qt/Display.h index de8c03648..f00bdb2b1 100644 --- a/src/platform/qt/Display.h +++ b/src/platform/qt/Display.h @@ -49,6 +49,7 @@ public: virtual bool supportsShaders() const = 0; virtual VideoShader* shaders() = 0; virtual VideoProxy* videoProxy() { return nullptr; } + virtual int framebufferHandle() { return -1; } signals: void showCursor(); diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index 8ff657016..6a3afecd6 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -18,7 +18,7 @@ #ifdef BUILD_GL #include "platform/opengl/gl.h" #endif -#if !defined(_WIN32) || defined(USE_EPOXY) +#ifdef BUILD_GLES2 #include "platform/opengl/gles2.h" #ifdef _WIN32 #include @@ -195,6 +195,10 @@ VideoProxy* DisplayGL::videoProxy() { return nullptr; } +int DisplayGL::framebufferHandle() { + return m_painter->glTex(); +} + PainterGL::PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent) : m_gl(parent) , m_videoProxy(proxy) @@ -202,7 +206,7 @@ PainterGL::PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent) #ifdef BUILD_GL mGLContext* glBackend; #endif -#if !defined(_WIN32) || defined(USE_EPOXY) +#ifdef BUILD_GLES2 mGLES2Context* gl2Backend; #endif @@ -213,7 +217,7 @@ PainterGL::PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent) QStringList extensions = QString(reinterpret_cast(glGetString(GL_EXTENSIONS))).split(' '); -#if !defined(_WIN32) || defined(USE_EPOXY) +#ifdef BUILD_GLES2 if (extensions.contains("GL_ARB_framebuffer_object") && majorVersion >= 2) { gl2Backend = static_cast(malloc(sizeof(mGLES2Context))); mGLES2ContextCreate(gl2Backend); @@ -239,7 +243,7 @@ PainterGL::PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent) }; m_backend->init(m_backend, reinterpret_cast(m_gl->winId())); -#if !defined(_WIN32) || defined(USE_EPOXY) +#ifdef BUILD_GLES2 if (m_supportsShaders) { m_shader.preprocessShader = static_cast(&reinterpret_cast(m_backend)->initialShader); } @@ -266,7 +270,7 @@ PainterGL::~PainterGL() { #if defined(_WIN32) && defined(USE_EPOXY) epoxy_handle_external_wglMakeCurrent(); #endif -#if !defined(_WIN32) || defined(USE_EPOXY) +#ifdef BUILD_GLES2 if (m_shader.passes) { mGLES2ShaderFree(&m_shader); } @@ -339,7 +343,7 @@ void PainterGL::start() { epoxy_handle_external_wglMakeCurrent(); #endif -#if !defined(_WIN32) || defined(USE_EPOXY) +#ifdef BUILD_GLES2 if (m_supportsShaders && m_shader.passes) { mGLES2ShaderAttach(reinterpret_cast(m_backend), static_cast(m_shader.passes), m_shader.nPasses); } @@ -422,14 +426,16 @@ void PainterGL::performDraw() { void PainterGL::enqueue(const uint32_t* backing) { m_mutex.lock(); - uint32_t* buffer; - if (m_free.isEmpty()) { - buffer = m_queue.dequeue(); - } else { - buffer = m_free.takeLast(); + uint32_t* buffer = nullptr; + if (backing) { + if (m_free.isEmpty()) { + buffer = m_queue.dequeue(); + } else { + buffer = m_free.takeLast(); + } + QSize size = m_context->screenDimensions(); + memcpy(buffer, backing, size.width() * size.height() * BYTES_PER_PIXEL); } - QSize size = m_context->screenDimensions(); - memcpy(buffer, backing, size.width() * size.height() * BYTES_PER_PIXEL); m_queue.enqueue(buffer); m_mutex.unlock(); } @@ -441,8 +447,10 @@ void PainterGL::dequeue() { return; } uint32_t* buffer = m_queue.dequeue(); - m_backend->postFrame(m_backend, buffer); - m_free.append(buffer); + if (buffer) { + m_backend->postFrame(m_backend, buffer); + m_free.append(buffer); + } m_mutex.unlock(); } @@ -451,7 +459,9 @@ void PainterGL::dequeueAll() { m_mutex.lock(); while (!m_queue.isEmpty()) { buffer = m_queue.dequeue(); - m_free.append(buffer); + if (buffer) { + m_free.append(buffer); + } } if (buffer) { m_backend->postFrame(m_backend, buffer); @@ -464,7 +474,7 @@ void PainterGL::setShaders(struct VDir* dir) { return; } if (!m_active) { -#if !defined(_WIN32) || defined(USE_EPOXY) +#ifdef BUILD_GLES2 m_gl->makeCurrent(); #if defined(_WIN32) && defined(USE_EPOXY) epoxy_handle_external_wglMakeCurrent(); @@ -489,7 +499,7 @@ void PainterGL::clearShaders() { return; } if (!m_active) { -#if !defined(_WIN32) || defined(USE_EPOXY) +#ifdef BUILD_GLES2 m_gl->makeCurrent(); #if defined(_WIN32) && defined(USE_EPOXY) epoxy_handle_external_wglMakeCurrent(); @@ -509,4 +519,19 @@ VideoShader* PainterGL::shaders() { return &m_shader; } +int PainterGL::glTex() { +#ifdef BUILD_GLES2 + if (supportsShaders()) { + mGLES2Context* gl2Backend = reinterpret_cast(m_backend); + return gl2Backend->tex; + } +#endif +#ifdef BUILD_GL + mGLContext* glBackend = reinterpret_cast(m_backend); + return glBackend->tex; +#else + return -1; +#endif +} + #endif diff --git a/src/platform/qt/DisplayGL.h b/src/platform/qt/DisplayGL.h index 8ef6f9e1c..990269fd0 100644 --- a/src/platform/qt/DisplayGL.h +++ b/src/platform/qt/DisplayGL.h @@ -52,6 +52,7 @@ public: bool supportsShaders() const override; VideoShader* shaders() override; VideoProxy* videoProxy() override; + int framebufferHandle() override; public slots: void stopDrawing() override; @@ -111,6 +112,8 @@ public slots: void clearShaders(); VideoShader* shaders(); + int glTex(); + private: void performDraw(); void dequeue(); diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index 379f5cecb..b0971ddc3 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -851,6 +851,10 @@ void Window::unimplementedBiosCall(int call) { void Window::reloadDisplayDriver() { if (m_controller) { + if (m_controller->hardwareAccelerated()) { + mustRestart(); + return; + } m_display->stopDrawing(); detachWidget(m_display.get()); } @@ -1715,8 +1719,15 @@ void Window::setController(CoreController* controller, const QString& fname) { reloadDisplayDriver(); } - if (m_display->videoProxy()) { - m_display->videoProxy()->attach(controller); + if (m_config->getOption("hwaccelVideo").toInt() && m_display->supportsShaders() && controller->supportsFeature(CoreController::Feature::OPENGL)) { + if (m_display->videoProxy()) { + m_display->videoProxy()->attach(controller); + } + + int fb = m_display->framebufferHandle(); + if (fb >= 0) { + controller->setFramebufferHandle(fb); + } } m_controller = std::shared_ptr(controller); diff --git a/src/platform/sdl/CMakeLists.txt b/src/platform/sdl/CMakeLists.txt index aa4c6cca5..36e73b686 100644 --- a/src/platform/sdl/CMakeLists.txt +++ b/src/platform/sdl/CMakeLists.txt @@ -77,12 +77,11 @@ if(BUILD_PANDORA) else() if(BUILD_GL) list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-sdl.c) - list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c) - include_directories(${OPENGL_INCLUDE_DIR}) + list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c) endif() if(BUILD_GLES2) list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gles2-sdl.c) - list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c) + list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c) include_directories(${OPENGLES2_INCLUDE_DIR}) endif() if(NOT BUILD_GL AND NOT BUILD_GLES2) diff --git a/src/platform/sdl/gles2-sdl.c b/src/platform/sdl/gles2-sdl.c index 6cc046769..675a1139c 100644 --- a/src/platform/sdl/gles2-sdl.c +++ b/src/platform/sdl/gles2-sdl.c @@ -35,7 +35,9 @@ bool mSDLGLES2Init(struct mSDLRenderer* renderer) { #endif size_t size = renderer->width * renderer->height * BYTES_PER_PIXEL; -#ifndef __APPLE__ +#ifdef _WIN32 + renderer->outputBuffer = _aligned_malloc(size, 16); +#elif !defined(__APPLE__) renderer->outputBuffer = memalign(16, size); #else posix_memalign((void**) &renderer->outputBuffer, 16, size); diff --git a/tools/sanitize-deb.sh b/tools/sanitize-deb.sh index d400f0489..df00f11dd 100755 --- a/tools/sanitize-deb.sh +++ b/tools/sanitize-deb.sh @@ -31,6 +31,7 @@ while [ $# -gt 0 ]; do rmdep libav rmdep libedit rmdep libelf + rmdep libgl rmdep libpng rmdep libzip rmdep libmagickwand @@ -45,6 +46,7 @@ while [ $# -gt 0 ]; do rmdep libav rmdep libedit rmdep libelf + rmdep libgl rmdep libpng rmdep qt rmdep libzip From bdc4e2837d7f82189e2342851ef3c67340df0741 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 14 May 2019 13:56:01 -0700 Subject: [PATCH 29/44] Qt: Add settings for enhancements --- src/platform/qt/SettingsView.cpp | 17 +++++++ src/platform/qt/SettingsView.h | 1 + src/platform/qt/SettingsView.ui | 83 +++++++++++++++++++++++++++++--- src/platform/qt/Window.cpp | 1 + 4 files changed, 95 insertions(+), 7 deletions(-) diff --git a/src/platform/qt/SettingsView.cpp b/src/platform/qt/SettingsView.cpp index c892efc63..3157ec6d3 100644 --- a/src/platform/qt/SettingsView.cpp +++ b/src/platform/qt/SettingsView.cpp @@ -401,6 +401,7 @@ void SettingsView::updateConfig() { saveSetting("logToStdout", m_ui.logToStdout); saveSetting("logFile", m_ui.logFile); saveSetting("useDiscordPresence", m_ui.useDiscordPresence); + saveSetting("audioHle", m_ui.audioHle); if (m_ui.fastForwardUnbounded->isChecked()) { saveSetting("fastForwardRatio", "-1"); @@ -465,6 +466,14 @@ void SettingsView::updateConfig() { emit languageChanged(); } + int videoScale = m_controller->getOption("videoScale").toInt(); + int hwaccelVideo = m_controller->getOption("hwaccelVideo").toInt(); + if (videoScale != m_ui.videoScale->value() || hwaccelVideo != m_ui.hwaccelVideo->currentIndex()) { + emit videoRendererChanged(); + } + saveSetting("videoScale", m_ui.videoScale); + saveSetting("hwaccelVideo", m_ui.hwaccelVideo->currentIndex()); + m_logModel.save(m_controller); m_logModel.logger()->setLogFile(m_ui.logFile->text()); m_logModel.logger()->logToFile(m_ui.logToFile->isChecked()); @@ -541,6 +550,8 @@ void SettingsView::reloadConfig() { loadSetting("logToStdout", m_ui.logToStdout); loadSetting("logFile", m_ui.logFile); loadSetting("useDiscordPresence", m_ui.useDiscordPresence); + loadSetting("audioHle", m_ui.audioHle); + loadSetting("videoScale", m_ui.videoScale); m_ui.libraryStyle->setCurrentIndex(loadSetting("libraryStyle").toInt()); @@ -604,6 +615,12 @@ void SettingsView::reloadConfig() { m_ui.cgbModel->setCurrentIndex(index >= 0 ? index : 0); } #endif + + int hwaccelVideo = m_controller->getOption("hwaccelVideo", 1).toInt(); + if (hwaccelVideo < 1) { + hwaccelVideo = 1; + } + m_ui.hwaccelVideo->setCurrentIndex(hwaccelVideo); } void SettingsView::saveSetting(const char* key, const QAbstractButton* field) { diff --git a/src/platform/qt/SettingsView.h b/src/platform/qt/SettingsView.h index b04d21805..0ea562807 100644 --- a/src/platform/qt/SettingsView.h +++ b/src/platform/qt/SettingsView.h @@ -40,6 +40,7 @@ signals: void displayDriverChanged(); void cameraDriverChanged(); void cameraChanged(const QByteArray&); + void videoRendererChanged(); void pathsChanged(); void languageChanged(); void libraryCleared(); diff --git a/src/platform/qt/SettingsView.ui b/src/platform/qt/SettingsView.ui index ea9cab924..15d7893f9 100644 --- a/src/platform/qt/SettingsView.ui +++ b/src/platform/qt/SettingsView.ui @@ -6,8 +6,8 @@ 0 0 - 588 - 488 + 790 + 686 @@ -33,14 +33,14 @@ - + 0 0 - 140 + 200 16777215 @@ -62,6 +62,11 @@ Emulation + + + Enhancements + + BIOS @@ -844,6 +849,70 @@ + + + + + + Video renderer: + + + + + + + + Software + + + + + OpenGL + + + + + + + + OpenGL enhancements + + + + + + High-resolution scale: + + + + + + + × + + + 1 + + + 13 + + + + + + + + + + false + + + XQ GBA audio (experimental) + + + + + @@ -1221,12 +1290,12 @@ - - 77 - 0 + + 77 + diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index b0971ddc3..15a13d3b9 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -460,6 +460,7 @@ void Window::openSettingsWindow() { connect(settingsWindow, &SettingsView::audioDriverChanged, this, &Window::reloadAudioDriver); connect(settingsWindow, &SettingsView::cameraDriverChanged, this, &Window::mustRestart); connect(settingsWindow, &SettingsView::cameraChanged, &m_inputController, &InputController::setCamera); + connect(settingsWindow, &SettingsView::videoRendererChanged, this, &Window::mustRestart); connect(settingsWindow, &SettingsView::languageChanged, this, &Window::mustRestart); connect(settingsWindow, &SettingsView::pathsChanged, this, &Window::reloadConfig); #ifdef USE_SQLITE3 From 945bc8fffe99d2cca5bfc646cffcb8c19fef52bb Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 14 May 2019 16:56:36 -0700 Subject: [PATCH 30/44] CMake: Fix Windows build issues --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b497822d..d25191081 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -476,12 +476,12 @@ if(NOT BUILD_GLES2) endif() if(BUILD_GL) list(APPEND OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gl.c) - list(APPEND OS_LIB ${OPENGL_LIBRARY}) + list(APPEND DEPENDENCY_LIB ${OPENGL_LIBRARY}) include_directories(${OPENGL_INCLUDE_DIR}) endif() if(BUILD_GLES2) list(APPEND OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gles2.c) - list(APPEND OS_LIB ${OPENGLES2_LIBRARY}) + list(APPEND DEPENDENCY_LIB ${OPENGLES2_LIBRARY}) include_directories(${OPENGLES2_INCLUDE_DIR}) endif() if(BUILD_GLES3) @@ -737,11 +737,13 @@ if (USE_LZMA) endif() if(USE_EPOXY) + list(APPEND OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gl.c ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gles2.c) add_definitions(-DBUILD_GL -DBUILD_GLES2) list(APPEND FEATURES EPOXY) include_directories(AFTER ${EPOXY_INCLUDE_DIRS}) link_directories(${EPOXY_LIBRARY_DIRS}) set(OPENGLES2_LIBRARY ${EPOXY_LIBRARIES}) + list(APPEND DEPENDENCY_LIB ${EPOXY_LIBRARIES}) set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libepoxy0") elseif(BUILD_GL) set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libgl1|libgles2") From 24929909f28df24461e62f36e80f0a60675facd3 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 14 May 2019 17:30:32 -0700 Subject: [PATCH 31/44] Qt: Reload GL context on main thread after shutting down painter --- src/platform/qt/DisplayGL.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index 6a3afecd6..a5f4129e9 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -99,6 +99,11 @@ void DisplayGL::stopDrawing() { QMetaObject::invokeMethod(m_painter, "stop", Qt::BlockingQueuedConnection); m_drawThread->exit(); m_drawThread = nullptr; + + m_gl->context()->makeCurrent(); +#if defined(_WIN32) && defined(USE_EPOXY) + epoxy_handle_external_wglMakeCurrent(); +#endif } m_context.reset(); } From 1baa9287f34855f9eaceab89eb7703cb928f5599 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 14 May 2019 18:04:51 -0700 Subject: [PATCH 32/44] Qt: Reduce flickering by resizing less often --- src/platform/qt/DisplayGL.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index a5f4129e9..2960e005f 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -316,6 +316,12 @@ void PainterGL::setMessagePainter(MessagePainter* messagePainter) { void PainterGL::resize(const QSize& size) { m_size = size; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + float r = m_gl->devicePixelRatioF(); +#else + float r = m_gl->devicePixelRatio(); +#endif + m_backend->resized(m_backend, m_size.width() * r, m_size.height() * r); if (m_started && !m_active) { forceDraw(); } @@ -323,16 +329,12 @@ void PainterGL::resize(const QSize& size) { void PainterGL::lockAspectRatio(bool lock) { m_backend->lockAspectRatio = lock; - if (m_started && !m_active) { - forceDraw(); - } + resize(m_size); } void PainterGL::lockIntegerScaling(bool lock) { m_backend->lockIntegerScaling = lock; - if (m_started && !m_active) { - forceDraw(); - } + resize(m_size); } void PainterGL::filter(bool filter) { @@ -416,12 +418,6 @@ void PainterGL::unpause() { void PainterGL::performDraw() { m_painter.beginNativePainting(); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) - float r = m_gl->devicePixelRatioF(); -#else - float r = m_gl->devicePixelRatio(); -#endif - m_backend->resized(m_backend, m_size.width() * r, m_size.height() * r); m_backend->drawFrame(m_backend); m_painter.endNativePainting(); if (m_messagePainter) { From 4bd788f7153ced2403def6478af29da7d0e3cbd5 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 14 May 2019 20:25:27 -0700 Subject: [PATCH 33/44] Qt: Port to QOpenGLWidget --- src/platform/qt/Display.cpp | 4 ++- src/platform/qt/DisplayGL.cpp | 63 ++++++++++++++++++----------------- src/platform/qt/DisplayGL.h | 23 +++++-------- src/platform/qt/main.cpp | 10 ++++++ 4 files changed, 53 insertions(+), 47 deletions(-) diff --git a/src/platform/qt/Display.cpp b/src/platform/qt/Display.cpp index fd91993bd..ee754c4f0 100644 --- a/src/platform/qt/Display.cpp +++ b/src/platform/qt/Display.cpp @@ -18,13 +18,15 @@ Display::Driver Display::s_driver = Display::Driver::QT; Display* Display::create(QWidget* parent) { #if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY) - QGLFormat format(QGLFormat(QGL::Rgba | QGL::DoubleBuffer)); + QSurfaceFormat format; format.setSwapInterval(1); + format.setSwapBehavior(QSurfaceFormat::TripleBuffer); #endif switch (s_driver) { #if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY) case Driver::OPENGL: + format.setVersion(3, 0); return new DisplayGL(format, parent); #endif #ifdef BUILD_GL diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index 2960e005f..81d01f960 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -10,8 +10,11 @@ #include "CoreController.h" #include +#include +#include #include #include +#include #include #include @@ -27,16 +30,17 @@ using namespace QGBA; -DisplayGL::DisplayGL(const QGLFormat& format, QWidget* parent) +DisplayGL::DisplayGL(const QSurfaceFormat& format, QWidget* parent) : Display(parent) , m_gl(nullptr) { // This can spontaneously re-enter into this->resizeEvent before creation is done, so we // need to make sure it's initialized to nullptr before we assign the new object to it - m_gl = new EmptyGLWidget(format, this); - m_painter = new PainterGL(format.majorVersion() < 2 ? 1 : m_gl->format().majorVersion(), &m_videoProxy, m_gl); - m_gl->setMouseTracking(true); - m_gl->setAttribute(Qt::WA_TransparentForMouseEvents); // This doesn't seem to work? + m_gl = new QOpenGLContext; + m_gl->setFormat(format); + m_gl->create(); + setAttribute(Qt::WA_NativeWindow); + m_painter = new PainterGL(&m_videoProxy, windowHandle(), m_gl); setUpdatesEnabled(false); // Prevent paint events, which can cause race conditions connect(&m_videoProxy, &VideoProxy::dataAvailable, &m_videoProxy, &VideoProxy::processData); @@ -46,6 +50,7 @@ DisplayGL::DisplayGL(const QGLFormat& format, QWidget* parent) DisplayGL::~DisplayGL() { stopDrawing(); delete m_painter; + delete m_gl; } bool DisplayGL::supportsShaders() const { @@ -71,11 +76,10 @@ void DisplayGL::startDrawing(std::shared_ptr controller) { m_painter->setMessagePainter(messagePainter()); m_context = controller; m_painter->resize(size()); - m_gl->move(0, 0); m_drawThread = new QThread(this); m_drawThread->setObjectName("Painter Thread"); - m_gl->context()->doneCurrent(); - m_gl->context()->moveToThread(m_drawThread); + m_gl->doneCurrent(); + m_gl->moveToThread(m_drawThread); m_painter->moveToThread(m_drawThread); m_videoProxy.moveToThread(m_drawThread); connect(m_drawThread, &QThread::started, m_painter, &PainterGL::start); @@ -100,7 +104,7 @@ void DisplayGL::stopDrawing() { m_drawThread->exit(); m_drawThread = nullptr; - m_gl->context()->makeCurrent(); + m_gl->makeCurrent(windowHandle()); #if defined(_WIN32) && defined(USE_EPOXY) epoxy_handle_external_wglMakeCurrent(); #endif @@ -185,9 +189,6 @@ void DisplayGL::resizeEvent(QResizeEvent* event) { } void DisplayGL::resizePainter() { - if (m_gl) { - m_gl->resize(size()); - } if (m_drawThread) { QMetaObject::invokeMethod(m_painter, "resize", Qt::BlockingQueuedConnection, Q_ARG(QSize, size())); } @@ -204,8 +205,9 @@ int DisplayGL::framebufferHandle() { return m_painter->glTex(); } -PainterGL::PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent) +PainterGL::PainterGL(VideoProxy* proxy, QWindow* surface, QOpenGLContext* parent) : m_gl(parent) + , m_surface(surface) , m_videoProxy(proxy) { #ifdef BUILD_GL @@ -215,10 +217,12 @@ PainterGL::PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent) mGLES2Context* gl2Backend; #endif - m_gl->makeCurrent(); + m_gl->makeCurrent(m_surface); + m_window = new QOpenGLPaintDevice; #if defined(_WIN32) && defined(USE_EPOXY) epoxy_handle_external_wglMakeCurrent(); #endif + int majorVersion = m_gl->format().majorVersion(); QStringList extensions = QString(reinterpret_cast(glGetString(GL_EXTENSIONS))).split(' '); @@ -241,13 +245,13 @@ PainterGL::PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent) #endif m_backend->swap = [](VideoBackend* v) { PainterGL* painter = static_cast(v->user); - if (!painter->m_gl->isVisible()) { + if (!painter->m_gl->isValid()) { return; } - painter->m_gl->swapBuffers(); + painter->m_gl->swapBuffers(painter->m_gl->surface()); }; - m_backend->init(m_backend, reinterpret_cast(m_gl->winId())); + m_backend->init(m_backend, 0); #ifdef BUILD_GLES2 if (m_supportsShaders) { m_shader.preprocessShader = static_cast(&reinterpret_cast(m_backend)->initialShader); @@ -271,7 +275,7 @@ PainterGL::~PainterGL() { for (auto item : m_free) { delete[] item; } - m_gl->makeCurrent(); + m_gl->makeCurrent(m_surface); #if defined(_WIN32) && defined(USE_EPOXY) epoxy_handle_external_wglMakeCurrent(); #endif @@ -284,6 +288,7 @@ PainterGL::~PainterGL() { m_gl->doneCurrent(); free(m_backend); m_backend = nullptr; + delete m_window; } void PainterGL::setContext(std::shared_ptr context) { @@ -297,7 +302,7 @@ void PainterGL::resizeContext() { } if (!m_active) { - m_gl->makeCurrent(); + m_gl->makeCurrent(m_surface); #if defined(_WIN32) && defined(USE_EPOXY) epoxy_handle_external_wglMakeCurrent(); #endif @@ -316,11 +321,7 @@ void PainterGL::setMessagePainter(MessagePainter* messagePainter) { void PainterGL::resize(const QSize& size) { m_size = size; -#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) - float r = m_gl->devicePixelRatioF(); -#else - float r = m_gl->devicePixelRatio(); -#endif + float r = m_surface->devicePixelRatio(); m_backend->resized(m_backend, m_size.width() * r, m_size.height() * r); if (m_started && !m_active) { forceDraw(); @@ -345,7 +346,7 @@ void PainterGL::filter(bool filter) { } void PainterGL::start() { - m_gl->makeCurrent(); + m_gl->makeCurrent(m_surface); #if defined(_WIN32) && defined(USE_EPOXY) epoxy_handle_external_wglMakeCurrent(); #endif @@ -368,7 +369,7 @@ void PainterGL::draw() { if (mCoreSyncWaitFrameStart(&m_context->thread()->impl->sync) || !m_queue.isEmpty()) { dequeue(); mCoreSyncWaitFrameEnd(&m_context->thread()->impl->sync); - m_painter.begin(m_gl->context()->device()); + m_painter.begin(m_window); performDraw(); m_painter.end(); m_backend->swap(m_backend); @@ -389,7 +390,7 @@ void PainterGL::draw() { } void PainterGL::forceDraw() { - m_painter.begin(m_gl->context()->device()); + m_painter.begin(m_window); performDraw(); m_painter.end(); m_backend->swap(m_backend); @@ -402,7 +403,7 @@ void PainterGL::stop() { m_backend->clear(m_backend); m_backend->swap(m_backend); m_gl->doneCurrent(); - m_gl->context()->moveToThread(m_gl->thread()); + m_gl->moveToThread(m_surface->thread()); m_context.reset(); moveToThread(m_gl->thread()); m_videoProxy->moveToThread(m_gl->thread()); @@ -474,9 +475,9 @@ void PainterGL::setShaders(struct VDir* dir) { if (!supportsShaders()) { return; } - if (!m_active) { #ifdef BUILD_GLES2 - m_gl->makeCurrent(); + if (!m_active) { + m_gl->makeCurrent(m_surface); #if defined(_WIN32) && defined(USE_EPOXY) epoxy_handle_external_wglMakeCurrent(); #endif @@ -501,7 +502,7 @@ void PainterGL::clearShaders() { } if (!m_active) { #ifdef BUILD_GLES2 - m_gl->makeCurrent(); + m_gl->makeCurrent(m_surface); #if defined(_WIN32) && defined(USE_EPOXY) epoxy_handle_external_wglMakeCurrent(); #endif diff --git a/src/platform/qt/DisplayGL.h b/src/platform/qt/DisplayGL.h index 990269fd0..2dbd1f2f0 100644 --- a/src/platform/qt/DisplayGL.h +++ b/src/platform/qt/DisplayGL.h @@ -17,9 +17,10 @@ #endif #include -#include +#include #include #include +#include #include #include @@ -29,22 +30,12 @@ namespace QGBA { -class EmptyGLWidget : public QGLWidget { -public: - EmptyGLWidget(const QGLFormat& format, QWidget* parent) : QGLWidget(format, parent) { setAutoBufferSwap(false); } - -protected: - void paintEvent(QPaintEvent* event) override { event->ignore(); } - void resizeEvent(QResizeEvent*) override {} - void mouseMoveEvent(QMouseEvent* event) override { event->ignore(); } -}; - class PainterGL; class DisplayGL : public Display { Q_OBJECT public: - DisplayGL(const QGLFormat& format, QWidget* parent = nullptr); + DisplayGL(const QSurfaceFormat& format, QWidget* parent = nullptr); ~DisplayGL(); void startDrawing(std::shared_ptr) override; @@ -75,7 +66,7 @@ private: void resizePainter(); bool m_isDrawing = false; - QGLWidget* m_gl; + QOpenGLContext* m_gl; PainterGL* m_painter; QThread* m_drawThread = nullptr; std::shared_ptr m_context; @@ -86,7 +77,7 @@ class PainterGL : public QObject { Q_OBJECT public: - PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent); + PainterGL(VideoProxy* proxy, QWindow* surface, QOpenGLContext* parent); ~PainterGL(); void setContext(std::shared_ptr); @@ -123,7 +114,9 @@ private: QQueue m_queue; QPainter m_painter; QMutex m_mutex; - QGLWidget* m_gl; + QWindow* m_surface; + QPaintDevice* m_window; + QOpenGLContext* m_gl; bool m_active = false; bool m_started = false; std::shared_ptr m_context = nullptr; diff --git a/src/platform/qt/main.cpp b/src/platform/qt/main.cpp index 9c3fa5072..e2659eae3 100644 --- a/src/platform/qt/main.cpp +++ b/src/platform/qt/main.cpp @@ -17,6 +17,10 @@ #include #include +#ifdef BUILD_GLES2 +#include +#endif + #ifdef QT_STATIC #include #ifdef Q_OS_WIN @@ -65,6 +69,12 @@ int main(int argc, char* argv[]) { QApplication::setApplicationName(projectName); QApplication::setApplicationVersion(projectVersion); +#ifdef BUILD_GLES2 + QSurfaceFormat format; + format.setVersion(3, 0); + QSurfaceFormat::setDefaultFormat(format); +#endif + GBAApp application(argc, argv, &configController); #ifndef Q_OS_MAC From ee6cd3640222dbd95f9f245a51ba1fa34aced9bd Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 14 May 2019 22:23:18 -0700 Subject: [PATCH 34/44] OpenGL: Use VAOs --- README.md | 2 +- include/mgba/internal/gba/renderers/gl.h | 20 ++-- src/gba/renderers/gl.c | 122 ++++++++++------------- src/platform/opengl/gles2.c | 20 +++- src/platform/opengl/gles2.h | 4 +- src/platform/qt/DisplayGL.cpp | 4 +- 6 files changed, 86 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index f07dc310d..b3350460a 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ Other Unix-like platforms, such as OpenBSD, are known to work as well, but are u ### System requirements -Requirements are minimal. Any computer that can run Windows Vista or newer should be able to handle emulation. Support for OpenGL 1.1 or newer is also required. +Requirements are minimal. Any computer that can run Windows Vista or newer should be able to handle emulation. Support for OpenGL 1.1 or newer is also required, with OpenGL 3.0 or newer for shaders and advanced features. Downloads --------- diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index 6ac96a50e..a59569b80 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -125,6 +125,12 @@ enum { GBA_GL_UNIFORM_MAX = 12 }; +struct GBAVideoGLShader { + GLuint program; + GLuint vao; + GLuint uniforms[GBA_GL_UNIFORM_MAX]; +}; + struct GBAVideoGLRenderer { struct GBAVideoRenderer d; @@ -136,6 +142,7 @@ struct GBAVideoGLRenderer { GLuint fbo[GBA_GL_FBO_MAX]; GLuint layers[GBA_GL_TEX_MAX]; + GLuint vbo; GLuint outputTex; @@ -148,15 +155,10 @@ struct GBAVideoGLRenderer { GLuint vramTex; unsigned vramDirty; - GLuint bgProgram[6]; - GLuint bgUniforms[6][GBA_GL_UNIFORM_MAX]; - GLuint objProgram[2]; - GLuint objUniforms[2][GBA_GL_UNIFORM_MAX]; - - GLuint compositeProgram; - GLuint compositeUniforms[GBA_GL_UNIFORM_MAX]; - GLuint finalizeProgram; - GLuint finalizeUniforms[GBA_GL_UNIFORM_MAX]; + struct GBAVideoGLShader bgShader[6]; + struct GBAVideoGLShader objShader[2]; + struct GBAVideoGLShader compositeShader; + struct GBAVideoGLShader finalizeShader; GBARegisterDISPCNT dispcnt; diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index bdd065cb8..1bfc1683e 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -399,7 +399,10 @@ void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) { renderer->scale = 1; } -void _compileShader(struct GBAVideoGLRenderer* glRenderer, GLuint program, const char** shaderBuffer, int shaderBufferLines, GLuint vs, char* log) { +void _compileShader(struct GBAVideoGLRenderer* glRenderer, struct GBAVideoGLShader* shader, const char** shaderBuffer, int shaderBufferLines, GLuint vs, const struct GBAVideoGLUniform* uniforms, char* log) { + GLuint program = glCreateProgram(); + shader->program = program; + GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); glAttachShader(program, vs); glAttachShader(program, fs); @@ -419,6 +422,18 @@ void _compileShader(struct GBAVideoGLRenderer* glRenderer, GLuint program, const glBindFragDataLocation(program, 0, "color"); glBindFragDataLocation(program, 1, "flags"); #endif + + glGenVertexArrays(1, &shader->vao); + glBindVertexArray(shader->vao); + glBindBuffer(GL_ARRAY_BUFFER, glRenderer->vbo); + GLuint positionLocation = glGetAttribLocation(program, "position"); + glVertexAttribPointer(positionLocation, 2, GL_INT, GL_FALSE, 0, NULL); + glEnableVertexAttribArray(positionLocation); + + size_t i; + for (i = 0; uniforms[i].name; ++i) { + shader->uniforms[uniforms[i].type] = glGetUniformLocation(program, uniforms[i].name); + } } static void _initFramebufferTexture(GLuint tex, GLenum format, GLenum attachment, int scale) { @@ -431,13 +446,6 @@ static void _initFramebufferTexture(GLuint tex, GLenum format, GLenum attachment glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex, 0); } -static void _lookupUniforms(GLuint program, GLuint* out, const struct GBAVideoGLUniform* uniforms) { - size_t i; - for (i = 0; uniforms[i].name; ++i) { - out[uniforms[i].type] = glGetUniformLocation(program, uniforms[i].name); - } -} - void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; glGenFramebuffers(GBA_GL_FBO_MAX, glRenderer->fbo); @@ -472,6 +480,10 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glBindFramebuffer(GL_FRAMEBUFFER, 0); + glGenBuffers(1, &glRenderer->vbo); + glBindBuffer(GL_ARRAY_BUFFER, glRenderer->vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(_vertices), _vertices, GL_STATIC_DRAW); + int i; for (i = 0; i < 4; ++i) { struct GBAVideoGLBackground* bg = &glRenderer->bg[i]; @@ -505,17 +517,6 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glBindFramebuffer(GL_FRAMEBUFFER, 0); } - glRenderer->compositeProgram = glCreateProgram(); - glRenderer->finalizeProgram = glCreateProgram(); - glRenderer->objProgram[0] = glCreateProgram(); - glRenderer->objProgram[1] = glCreateProgram(); - glRenderer->bgProgram[0] = glCreateProgram(); - glRenderer->bgProgram[1] = glCreateProgram(); - glRenderer->bgProgram[2] = glCreateProgram(); - glRenderer->bgProgram[3] = glCreateProgram(); - glRenderer->bgProgram[4] = glCreateProgram(); - glRenderer->bgProgram[5] = glCreateProgram(); - char log[1024]; const GLchar* shaderBuffer[8]; shaderBuffer[0] = _gl3Header; @@ -532,51 +533,44 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { shaderBuffer[1] = _renderMode0; shaderBuffer[2] = _renderTile16; - _compileShader(glRenderer, glRenderer->bgProgram[0], shaderBuffer, 3, vs, log); - _lookupUniforms(glRenderer->bgProgram[0], glRenderer->bgUniforms[0], _uniformsMode0); + _compileShader(glRenderer, &glRenderer->bgShader[0], shaderBuffer, 3, vs, _uniformsMode0, log); shaderBuffer[2] = _renderTile256; - _compileShader(glRenderer, glRenderer->bgProgram[1], shaderBuffer, 3, vs, log); - _lookupUniforms(glRenderer->bgProgram[1], glRenderer->bgUniforms[1], _uniformsMode0); + _compileShader(glRenderer, &glRenderer->bgShader[1], shaderBuffer, 3, vs, _uniformsMode0, log); shaderBuffer[1] = _renderMode2; shaderBuffer[2] = _fetchTileOverflow; - _compileShader(glRenderer, glRenderer->bgProgram[2], shaderBuffer, 3, vs, log); - _lookupUniforms(glRenderer->bgProgram[2], glRenderer->bgUniforms[2], _uniformsMode2); + _compileShader(glRenderer, &glRenderer->bgShader[2], shaderBuffer, 3, vs, _uniformsMode2, log); shaderBuffer[2] = _fetchTileNoOverflow; - _compileShader(glRenderer, glRenderer->bgProgram[3], shaderBuffer, 3, vs, log); - _lookupUniforms(glRenderer->bgProgram[3], glRenderer->bgUniforms[3], _uniformsMode2); + _compileShader(glRenderer, &glRenderer->bgShader[3], shaderBuffer, 3, vs, _uniformsMode2, log); shaderBuffer[1] = _renderObj; shaderBuffer[2] = _renderTile16; - _compileShader(glRenderer, glRenderer->objProgram[0], shaderBuffer, 3, vs, log); - _lookupUniforms(glRenderer->objProgram[0], glRenderer->objUniforms[0], _uniformsObj); + _compileShader(glRenderer, &glRenderer->objShader[0], shaderBuffer, 3, vs, _uniformsObj, log); #ifndef BUILD_GLES3 - glBindFragDataLocation(glRenderer->objProgram[0], 2, "window"); + glBindFragDataLocation(glRenderer->objShader[0].program, 2, "window"); #endif shaderBuffer[2] = _renderTile256; - _compileShader(glRenderer, glRenderer->objProgram[1], shaderBuffer, 3, vs, log); - _lookupUniforms(glRenderer->objProgram[1], glRenderer->objUniforms[1], _uniformsObj); + _compileShader(glRenderer, &glRenderer->objShader[1], shaderBuffer, 3, vs, _uniformsObj, log); #ifndef BUILD_GLES3 - glBindFragDataLocation(glRenderer->objProgram[1], 2, "window"); + glBindFragDataLocation(glRenderer->objShader[1].program, 2, "window"); #endif shaderBuffer[1] = _composite; - _compileShader(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log); - _lookupUniforms(glRenderer->compositeProgram, glRenderer->compositeUniforms, _uniformsComposite); + _compileShader(glRenderer, &glRenderer->compositeShader, shaderBuffer, 2, vs, _uniformsComposite, log); #ifndef BUILD_GLES3 - glBindFragDataLocation(glRenderer->compositeProgram, 2, "oldColor"); - glBindFragDataLocation(glRenderer->compositeProgram, 3, "oldFlags"); + glBindFragDataLocation(glRenderer->compositeShader.program, 2, "oldColor"); + glBindFragDataLocation(glRenderer->compositeShader.program, 3, "oldFlags"); #endif shaderBuffer[1] = _finalize; - _compileShader(glRenderer, glRenderer->finalizeProgram, shaderBuffer, 2, vs, log); - _lookupUniforms(glRenderer->finalizeProgram, glRenderer->finalizeUniforms, _uniformsFinalize); + _compileShader(glRenderer, &glRenderer->finalizeShader, shaderBuffer, 2, vs, _uniformsFinalize, log); + glBindVertexArray(0); glDeleteShader(vs); GBAVideoGLRendererReset(renderer); @@ -588,16 +582,6 @@ void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { glDeleteTextures(GBA_GL_TEX_MAX, glRenderer->layers); glDeleteTextures(1, &glRenderer->paletteTex); glDeleteTextures(1, &glRenderer->vramTex); - - glDeleteProgram(glRenderer->bgProgram[0]); - glDeleteProgram(glRenderer->bgProgram[1]); - glDeleteProgram(glRenderer->bgProgram[2]); - glDeleteProgram(glRenderer->bgProgram[3]); - glDeleteProgram(glRenderer->bgProgram[4]); - glDeleteProgram(glRenderer->bgProgram[5]); - glDeleteProgram(glRenderer->objProgram[0]); - glDeleteProgram(glRenderer->objProgram[1]); - glDeleteProgram(glRenderer->compositeProgram); } void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) { @@ -1075,11 +1059,12 @@ static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLu if ((y & 0x1F) != 0x1F) { return; } - const GLuint* uniforms = renderer->compositeUniforms; + const GLuint* uniforms = renderer->compositeShader.uniforms; glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_COMPOSITE]); glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); glScissor(0, (y & ~0x1F) * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale); - glUseProgram(renderer->compositeProgram); + glUseProgram(renderer->compositeShader.program); + glBindVertexArray(renderer->compositeShader.vao); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); glActiveTexture(GL_TEXTURE0 + 1); @@ -1102,23 +1087,21 @@ static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLu glUniform1i(uniforms[GBA_GL_COMPOSITE_OLDLAYERFLAGS], 3); glUniform1i(uniforms[GBA_GL_COMPOSITE_OLDOLDFLAGS], 4); glUniform1i(uniforms[GBA_GL_COMPOSITE_WINDOW], 5); - glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); - glEnableVertexAttribArray(0); glDrawBuffers(4, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 }); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); - glBindFramebuffer(GL_FRAMEBUFFER, 0); } void _finalizeLayers(struct GBAVideoGLRenderer* renderer, int y) { if ((y & 0x1F) != 0x1F) { return; } - const GLuint* uniforms = renderer->finalizeUniforms; + const GLuint* uniforms = renderer->finalizeShader.uniforms; glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OUTPUT]); glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); glScissor(0, (y & ~0x1F) * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale); - glUseProgram(renderer->finalizeProgram); + glUseProgram(renderer->finalizeShader.program); + glBindVertexArray(renderer->finalizeShader.vao); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_COLOR]); glActiveTexture(GL_TEXTURE0 + 1); @@ -1134,8 +1117,6 @@ void _finalizeLayers(struct GBAVideoGLRenderer* renderer, int y) { glUniform1i(uniforms[GBA_GL_FINALIZE_LAYERFLAGS], 1); glUniform1i(uniforms[GBA_GL_FINALIZE_OLDLAYER], 2); glUniform1i(uniforms[GBA_GL_FINALIZE_OLDFLAGS], 3); - glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); - glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -1167,11 +1148,13 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB enum GBAVideoBlendEffect blendEffect = GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT ? BLEND_ALPHA : renderer->blendEffect; - const GLuint* uniforms = renderer->objUniforms[GBAObjAttributesAGet256Color(sprite->a)]; + const struct GBAVideoGLShader* shader = &renderer->objShader[GBAObjAttributesAGet256Color(sprite->a)]; + const GLuint* uniforms = shader->uniforms; glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OBJ]); glViewport(x * renderer->scale, spriteY * renderer->scale, totalWidth * renderer->scale, totalHeight * renderer->scale); glScissor(x * renderer->scale, y * renderer->scale, totalWidth * renderer->scale, renderer->scale); - glUseProgram(renderer->objProgram[GBAObjAttributesAGet256Color(sprite->a)]); + glUseProgram(shader->program); + glBindVertexArray(shader->vao); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, renderer->vramTex); glActiveTexture(GL_TEXTURE0 + 1); @@ -1198,8 +1181,6 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB glUniformMatrix2fv(uniforms[GBA_GL_OBJ_TRANSFORM], 1, GL_FALSE, (GLfloat[]) { 1.f, 0, 0, 1.f }); } glUniform4i(uniforms[GBA_GL_OBJ_DIMS], width, height, totalWidth, totalHeight); - glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); - glEnableVertexAttribArray(0); if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_OBJWIN) { int window = ~renderer->objwin & 0xFF; glUniform3f(uniforms[GBA_GL_OBJ_OBJWIN], 1, (window & 0xF) / 32.f, (window >> 4) / 32.f); @@ -1220,11 +1201,14 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, } else if (background->size == 3) { yBase += (inY & 0x100) << 1; } - const GLuint* uniforms = renderer->bgUniforms[background->multipalette ? 1 : 0]; + + const struct GBAVideoGLShader* shader = &renderer->bgShader[background->multipalette ? 1 : 0]; + const GLuint* uniforms = shader->uniforms; glBindFramebuffer(GL_FRAMEBUFFER, background->fbo); glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); glScissor(0, y * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale); - glUseProgram(renderer->bgProgram[background->multipalette ? 1 : 0]); + glUseProgram(shader->program); + glBindVertexArray(shader->vao); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, renderer->vramTex); glActiveTexture(GL_TEXTURE0 + 1); @@ -1240,8 +1224,6 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, glUniform4i(uniforms[GBA_GL_BG_INFLAGS], (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2) | (renderer->blendEffect * 4), renderer->blendEffect == BLEND_ALPHA ? renderer->blda : renderer->bldy, renderer->bldb); - glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); - glEnableVertexAttribArray(0); glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); @@ -1250,11 +1232,13 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, } void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { - const GLuint* uniforms = renderer->bgUniforms[background->overflow ? 2 : 3]; + const struct GBAVideoGLShader* shader = &renderer->bgShader[background->overflow ? 2 : 3]; + const GLuint* uniforms = shader->uniforms; glBindFramebuffer(GL_FRAMEBUFFER, background->fbo); glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); glScissor(0, y * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale); - glUseProgram(renderer->bgProgram[background->overflow ? 2 : 3]); + glUseProgram(shader->program); + glBindVertexArray(shader->vao); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, renderer->vramTex); glActiveTexture(GL_TEXTURE0 + 1); @@ -1296,8 +1280,6 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, background->affine[0].dx, background->affine[0].dy, }); } - glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); - glEnableVertexAttribArray(0); glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); diff --git a/src/platform/opengl/gles2.c b/src/platform/opengl/gles2.c index 94d0856ca..da09ecd60 100644 --- a/src/platform/opengl/gles2.c +++ b/src/platform/opengl/gles2.c @@ -84,6 +84,10 @@ static void mGLES2ContextInit(struct VideoBackend* v, WHandle handle) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glGenBuffers(1, &context->vbo); + glBindBuffer(GL_ARRAY_BUFFER, context->vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(_vertices), _vertices, GL_STATIC_DRAW); + glClearColor(0.f, 0.f, 0.f, 1.f); struct mGLES2Uniform* uniforms = malloc(sizeof(struct mGLES2Uniform) * 4); @@ -159,6 +163,7 @@ static void mGLES2ContextSetDimensions(struct VideoBackend* v, unsigned width, u static void mGLES2ContextDeinit(struct VideoBackend* v) { struct mGLES2Context* context = (struct mGLES2Context*) v; glDeleteTextures(1, &context->tex); + glDeleteBuffers(1, &context->vbo); mGLES2ShaderDeinit(&context->initialShader); mGLES2ShaderDeinit(&context->finalShader); free(context->initialShader.uniforms); @@ -239,8 +244,7 @@ void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) { glUseProgram(shader->program); glUniform1i(shader->texLocation, 0); glUniform2f(shader->texSizeLocation, context->d.width - padW, context->d.height - padH); - glVertexAttribPointer(shader->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices); - glEnableVertexAttribArray(shader->positionLocation); + glBindVertexArray(shader->vao); size_t u; for (u = 0; u < shader->nUniforms; ++u) { struct mGLES2Uniform* uniform = &shader->uniforms[u]; @@ -420,6 +424,13 @@ void mGLES2ShaderInit(struct mGLES2Shader* shader, const char* vs, const char* f for (i = 0; i < shader->nUniforms; ++i) { shader->uniforms[i].location = glGetUniformLocation(shader->program, shader->uniforms[i].name); } + + glGenVertexArrays(1, &shader->vao); + glBindVertexArray(shader->vao); + glVertexAttribPointer(shader->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL); + glEnableVertexAttribArray(shader->positionLocation); + glBindVertexArray(0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -428,6 +439,7 @@ void mGLES2ShaderDeinit(struct mGLES2Shader* shader) { glDeleteShader(shader->fragmentShader); glDeleteProgram(shader->program); glDeleteFramebuffers(1, &shader->fbo); + glDeleteVertexArrays(1, &shader->vao); } void mGLES2ShaderAttach(struct mGLES2Context* context, struct mGLES2Shader* shaders, size_t nShaders) { @@ -443,7 +455,11 @@ void mGLES2ShaderAttach(struct mGLES2Context* context, struct mGLES2Shader* shad for (i = 0; i < nShaders; ++i) { glBindFramebuffer(GL_FRAMEBUFFER, context->shaders[i].fbo); glClear(GL_COLOR_BUFFER_BIT); + + glBindVertexArray(context->shaders[i].vao); + glBindBuffer(GL_ARRAY_BUFFER, context->vbo); } + glBindVertexArray(0); glBindFramebuffer(GL_FRAMEBUFFER, 0); } diff --git a/src/platform/opengl/gles2.h b/src/platform/opengl/gles2.h index f6d050bc9..59f3b7996 100644 --- a/src/platform/opengl/gles2.h +++ b/src/platform/opengl/gles2.h @@ -62,6 +62,7 @@ struct mGLES2Shader { bool blend; GLuint tex; GLuint fbo; + GLuint vao; GLuint fragmentShader; GLuint vertexShader; GLuint program; @@ -77,8 +78,7 @@ struct mGLES2Context { struct VideoBackend d; GLuint tex; - GLuint texLocation; - GLuint positionLocation; + GLuint vbo; struct mGLES2Shader initialShader; struct mGLES2Shader finalShader; diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index 81d01f960..2405cbe07 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -227,7 +227,7 @@ PainterGL::PainterGL(VideoProxy* proxy, QWindow* surface, QOpenGLContext* parent QStringList extensions = QString(reinterpret_cast(glGetString(GL_EXTENSIONS))).split(' '); #ifdef BUILD_GLES2 - if (extensions.contains("GL_ARB_framebuffer_object") && majorVersion >= 2) { + if ((majorVersion == 2 && extensions.contains("GL_ARB_framebuffer_object")) || majorVersion > 2) { gl2Backend = static_cast(malloc(sizeof(mGLES2Context))); mGLES2ContextCreate(gl2Backend); m_backend = &gl2Backend->d; @@ -500,8 +500,8 @@ void PainterGL::clearShaders() { if (!supportsShaders()) { return; } - if (!m_active) { #ifdef BUILD_GLES2 + if (!m_active) { m_gl->makeCurrent(m_surface); #if defined(_WIN32) && defined(USE_EPOXY) epoxy_handle_external_wglMakeCurrent(); From 3797e1e5f6b001fa1cb2855304c752d81ef25ff6 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 14 May 2019 22:44:00 -0700 Subject: [PATCH 35/44] GBA Video: Minor GL cleanup --- src/gba/renderers/gl.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 1bfc1683e..d28510014 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -856,16 +856,12 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { glClear(GL_COLOR_BUFFER_BIT); glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]); - glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); - glClear(GL_COLOR_BUFFER_BIT); - glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT1 }); + glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); glClear(GL_COLOR_BUFFER_BIT); for (i = 0; i < 4; ++i) { glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo); - glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); - glClear(GL_COLOR_BUFFER_BIT); - glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT1 }); + glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); glClear(GL_COLOR_BUFFER_BIT); } glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); @@ -890,6 +886,7 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { glRenderer->firstAffine = -1; } + GBAVideoGLRendererDrawWindow(glRenderer, y); if (GBARegisterDISPCNTIsObjEnable(glRenderer->dispcnt) && !glRenderer->d.disableOBJ) { if (glRenderer->oamDirty) { glRenderer->oamMax = GBAVideoRendererCleanOAM(glRenderer->d.oam->obj, glRenderer->sprites, 0); @@ -906,7 +903,6 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } } - GBAVideoGLRendererDrawWindow(glRenderer, y); _compositeLayer(glRenderer, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], 4, y); unsigned priority; for (priority = 4; priority--;) { From 06cc738b008cb0017965b14013c3039bdd430df8 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 14 May 2019 23:33:54 -0700 Subject: [PATCH 36/44] GBA Video: Fix VAOs on Nvidia --- src/gba/renderers/gl.c | 6 +++++- src/platform/opengl/gles2.c | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index d28510014..5a8521d81 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -428,7 +428,6 @@ void _compileShader(struct GBAVideoGLRenderer* glRenderer, struct GBAVideoGLShad glBindBuffer(GL_ARRAY_BUFFER, glRenderer->vbo); GLuint positionLocation = glGetAttribLocation(program, "position"); glVertexAttribPointer(positionLocation, 2, GL_INT, GL_FALSE, 0, NULL); - glEnableVertexAttribArray(positionLocation); size_t i; for (i = 0; uniforms[i].name; ++i) { @@ -1084,6 +1083,7 @@ static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLu glUniform1i(uniforms[GBA_GL_COMPOSITE_OLDOLDFLAGS], 4); glUniform1i(uniforms[GBA_GL_COMPOSITE_WINDOW], 5); glDrawBuffers(4, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 }); + glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); } @@ -1113,6 +1113,7 @@ void _finalizeLayers(struct GBAVideoGLRenderer* renderer, int y) { glUniform1i(uniforms[GBA_GL_FINALIZE_LAYERFLAGS], 1); glUniform1i(uniforms[GBA_GL_FINALIZE_OLDLAYER], 2); glUniform1i(uniforms[GBA_GL_FINALIZE_OLDFLAGS], 3); + glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -1185,6 +1186,7 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB glUniform3f(uniforms[GBA_GL_OBJ_OBJWIN], 0, 0, 0); glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); } + glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); } @@ -1221,6 +1223,7 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, background->target1 | (background->target2 * 2) | (renderer->blendEffect * 4), renderer->blendEffect == BLEND_ALPHA ? renderer->blda : renderer->bldy, renderer->bldb); glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); + glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); @@ -1277,6 +1280,7 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, }); } glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); + glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); diff --git a/src/platform/opengl/gles2.c b/src/platform/opengl/gles2.c index da09ecd60..d51dd568f 100644 --- a/src/platform/opengl/gles2.c +++ b/src/platform/opengl/gles2.c @@ -135,6 +135,15 @@ static void mGLES2ContextInit(struct VideoBackend* v, WHandle handle) { uniforms[3].max.fvec3[2] = 1.0f; mGLES2ShaderInit(&context->initialShader, _vertexShader, _fragmentShader, -1, -1, false, uniforms, 4); mGLES2ShaderInit(&context->finalShader, 0, 0, 0, 0, false, 0, 0); + + glBindVertexArray(context->initialShader.vao); + glBindBuffer(GL_ARRAY_BUFFER, context->vbo); + glVertexAttribPointer(context->initialShader.positionLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL); + glBindVertexArray(context->finalShader.vao); + glBindBuffer(GL_ARRAY_BUFFER, context->vbo); + glVertexAttribPointer(context->finalShader.positionLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL); + glBindVertexArray(0); + glDeleteFramebuffers(1, &context->finalShader.fbo); glDeleteTextures(1, &context->finalShader.tex); context->finalShader.fbo = 0; @@ -296,6 +305,7 @@ void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) { break; } } + glEnableVertexAttribArray(shader->positionLocation); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glBindTexture(GL_TEXTURE_2D, shader->tex); } @@ -426,10 +436,6 @@ void mGLES2ShaderInit(struct mGLES2Shader* shader, const char* vs, const char* f } glGenVertexArrays(1, &shader->vao); - glBindVertexArray(shader->vao); - glVertexAttribPointer(shader->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL); - glEnableVertexAttribArray(shader->positionLocation); - glBindVertexArray(0); glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -458,6 +464,8 @@ void mGLES2ShaderAttach(struct mGLES2Context* context, struct mGLES2Shader* shad glBindVertexArray(context->shaders[i].vao); glBindBuffer(GL_ARRAY_BUFFER, context->vbo); + glVertexAttribPointer(context->shaders[i].positionLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL); + glEnableVertexAttribArray(context->shaders[i].positionLocation); } glBindVertexArray(0); glBindFramebuffer(GL_FRAMEBUFFER, 0); From 99d07c98c5d03510899c50a67573498900cddfef Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 15 May 2019 10:16:06 -0700 Subject: [PATCH 37/44] OpenGL: Fix frame sizing regression --- src/platform/opengl/gles2.c | 5 ++--- src/platform/qt/DisplayGL.cpp | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/platform/opengl/gles2.c b/src/platform/opengl/gles2.c index d51dd568f..465820528 100644 --- a/src/platform/opengl/gles2.c +++ b/src/platform/opengl/gles2.c @@ -192,14 +192,13 @@ static void mGLES2ContextResized(struct VideoBackend* v, unsigned w, unsigned h) drawW -= drawW % v->width; drawH -= drawH % v->height; } - glViewport(0, 0, w, h); - glClearColor(0.f, 0.f, 0.f, 1.f); - glClear(GL_COLOR_BUFFER_BIT); + glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH); } static void mGLES2ContextClear(struct VideoBackend* v) { UNUSED(v); + glBindFramebuffer(GL_FRAMEBUFFER, 0); glClearColor(0.f, 0.f, 0.f, 1.f); glClear(GL_COLOR_BUFFER_BIT); } diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index 2405cbe07..0df112e06 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -321,8 +321,6 @@ void PainterGL::setMessagePainter(MessagePainter* messagePainter) { void PainterGL::resize(const QSize& size) { m_size = size; - float r = m_surface->devicePixelRatio(); - m_backend->resized(m_backend, m_size.width() * r, m_size.height() * r); if (m_started && !m_active) { forceDraw(); } @@ -419,6 +417,8 @@ void PainterGL::unpause() { void PainterGL::performDraw() { m_painter.beginNativePainting(); + float r = m_surface->devicePixelRatio(); + m_backend->resized(m_backend, m_size.width() * r, m_size.height() * r); m_backend->drawFrame(m_backend); m_painter.endNativePainting(); if (m_messagePainter) { From cecf6adb2c5e60a847a75050917a0d47ec889466 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 15 May 2019 10:42:21 -0700 Subject: [PATCH 38/44] GBA Video: Fix 256-color sprites in GL renderer --- src/gba/renderers/gl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 5a8521d81..7dfb40287 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -1126,7 +1126,7 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB int align = GBAObjAttributesAIs256Color(sprite->a) && !GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt); unsigned charBase = (BASE_TILE >> 1) + (GBAObjAttributesCGetTile(sprite->c) & ~align) * 0x10; - int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> 3) : (0x40 >> !GBAObjAttributesAIs256Color(sprite->a)); + int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> 3) : (0x20 >> GBAObjAttributesAGet256Color(sprite->a)); if (spriteY + height >= 256) { spriteY -= 256; From 505d63fab55ff83c7487a4162e7f932fae0e4df1 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 15 May 2019 10:42:39 -0700 Subject: [PATCH 39/44] Qt: Fix hwaccel settings --- src/platform/qt/SettingsView.cpp | 13 +++++-------- src/platform/qt/SettingsView.h | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/platform/qt/SettingsView.cpp b/src/platform/qt/SettingsView.cpp index 3157ec6d3..95943c671 100644 --- a/src/platform/qt/SettingsView.cpp +++ b/src/platform/qt/SettingsView.cpp @@ -466,7 +466,7 @@ void SettingsView::updateConfig() { emit languageChanged(); } - int videoScale = m_controller->getOption("videoScale").toInt(); + int videoScale = m_controller->getOption("videoScale", 1).toInt(); int hwaccelVideo = m_controller->getOption("hwaccelVideo").toInt(); if (videoScale != m_ui.videoScale->value() || hwaccelVideo != m_ui.hwaccelVideo->currentIndex()) { emit videoRendererChanged(); @@ -551,7 +551,7 @@ void SettingsView::reloadConfig() { loadSetting("logFile", m_ui.logFile); loadSetting("useDiscordPresence", m_ui.useDiscordPresence); loadSetting("audioHle", m_ui.audioHle); - loadSetting("videoScale", m_ui.videoScale); + loadSetting("videoScale", m_ui.videoScale, 1); m_ui.libraryStyle->setCurrentIndex(loadSetting("libraryStyle").toInt()); @@ -616,10 +616,7 @@ void SettingsView::reloadConfig() { } #endif - int hwaccelVideo = m_controller->getOption("hwaccelVideo", 1).toInt(); - if (hwaccelVideo < 1) { - hwaccelVideo = 1; - } + int hwaccelVideo = m_controller->getOption("hwaccelVideo", 0).toInt(); m_ui.hwaccelVideo->setCurrentIndex(hwaccelVideo); } @@ -677,9 +674,9 @@ void SettingsView::loadSetting(const char* key, QSlider* field, int defaultVal) field->setValue(option.isNull() ? defaultVal : option.toInt()); } -void SettingsView::loadSetting(const char* key, QSpinBox* field) { +void SettingsView::loadSetting(const char* key, QSpinBox* field, int defaultVal) { QString option = loadSetting(key); - field->setValue(option.toInt()); + field->setValue(option.isNull() ? defaultVal : option.toInt()); } QString SettingsView::loadSetting(const char* key) { diff --git a/src/platform/qt/SettingsView.h b/src/platform/qt/SettingsView.h index 0ea562807..23a8c18ff 100644 --- a/src/platform/qt/SettingsView.h +++ b/src/platform/qt/SettingsView.h @@ -77,7 +77,7 @@ private: void loadSetting(const char* key, QDoubleSpinBox*); void loadSetting(const char* key, QLineEdit*); void loadSetting(const char* key, QSlider*, int defaultVal = 0); - void loadSetting(const char* key, QSpinBox*); + void loadSetting(const char* key, QSpinBox*, int defaultVal = 0); QString loadSetting(const char* key); }; From 25f0bc7f2be32fdff2190b563d3bf996279a64fb Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 15 May 2019 23:43:01 -0700 Subject: [PATCH 40/44] GBA Video: Massively simplify compositing --- include/mgba/internal/gba/renderers/gl.h | 28 +- src/gba/renderers/gl.c | 350 +++++++++-------------- 2 files changed, 148 insertions(+), 230 deletions(-) diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index a59569b80..4b1c4a07f 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -67,19 +67,14 @@ struct GBAVideoGLBackground { enum { GBA_GL_FBO_OBJ = 0, - GBA_GL_FBO_COMPOSITE = 1, - GBA_GL_FBO_WINDOW = 2, - GBA_GL_FBO_OUTPUT = 3, + GBA_GL_FBO_WINDOW = 1, + GBA_GL_FBO_OUTPUT = 2, GBA_GL_FBO_MAX }; enum { GBA_GL_TEX_OBJ_COLOR = 0, GBA_GL_TEX_OBJ_FLAGS = 1, - GBA_GL_TEX_COMPOSITE_COLOR = 2, - GBA_GL_TEX_COMPOSITE_FLAGS = 3, - GBA_GL_TEX_COMPOSITE_OLD_COLOR = 4, - GBA_GL_TEX_COMPOSITE_OLD_FLAGS = 5, GBA_GL_TEX_WINDOW = 6, GBA_GL_TEX_MAX }; @@ -107,20 +102,12 @@ enum { GBA_GL_OBJ_DIMS, GBA_GL_OBJ_OBJWIN, - GBA_GL_COMPOSITE_SCALE = 2, - GBA_GL_COMPOSITE_LAYERID, - GBA_GL_COMPOSITE_LAYER, - GBA_GL_COMPOSITE_LAYERFLAGS, - GBA_GL_COMPOSITE_OLDLAYER, - GBA_GL_COMPOSITE_OLDLAYERFLAGS, - GBA_GL_COMPOSITE_OLDOLDFLAGS, - GBA_GL_COMPOSITE_WINDOW, - GBA_GL_FINALIZE_SCALE = 2, - GBA_GL_FINALIZE_LAYER, - GBA_GL_FINALIZE_LAYERFLAGS, - GBA_GL_FINALIZE_OLDLAYER, - GBA_GL_FINALIZE_OLDFLAGS, + GBA_GL_FINALIZE_LAYERS, + GBA_GL_FINALIZE_FLAGS, + GBA_GL_FINALIZE_WINDOW, + GBA_GL_FINALIZE_BACKDROP, + GBA_GL_FINALIZE_BACKDROPFLAGS, GBA_GL_UNIFORM_MAX = 12 }; @@ -157,7 +144,6 @@ struct GBAVideoGLRenderer { struct GBAVideoGLShader bgShader[6]; struct GBAVideoGLShader objShader[2]; - struct GBAVideoGLShader compositeShader; struct GBAVideoGLShader finalizeShader; GBARegisterDISPCNT dispcnt; diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 7dfb40287..1aa811485 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -40,10 +40,9 @@ static void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* ren static void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); static void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y); -static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int id, int y); static void _finalizeLayers(struct GBAVideoGLRenderer* renderer, int y); -#define TEST_LAYER_ENABLED(X) !renderer->disableBG[X] && glRenderer->bg[X].enabled == 4 && glRenderer->bg[X].priority == priority +#define TEST_LAYER_ENABLED(X) !renderer->disableBG[X] && glRenderer->bg[X].enabled == 4 struct GBAVideoGLUniform { const char* name; @@ -270,104 +269,93 @@ static const char* const _renderObj = " window = objwin.yz;\n" "}"; -static const struct GBAVideoGLUniform _uniformsComposite[] = { - { "loc", GBA_GL_VS_LOC, }, - { "maxPos", GBA_GL_VS_MAXPOS, }, - { "scale", GBA_GL_COMPOSITE_SCALE, }, - { "layerId", GBA_GL_COMPOSITE_LAYERID, }, - { "layer", GBA_GL_COMPOSITE_LAYER, }, - { "layerFlags", GBA_GL_COMPOSITE_LAYERFLAGS, }, - { "oldLayer", GBA_GL_COMPOSITE_OLDLAYER, }, - { "oldLayerFlags", GBA_GL_COMPOSITE_OLDLAYERFLAGS, }, - { "oldOldFlags", GBA_GL_COMPOSITE_OLDOLDFLAGS, }, - { "window", GBA_GL_COMPOSITE_WINDOW, }, - { 0 } -}; - -static const char* const _composite = - "in vec2 texCoord;\n" - "uniform int scale;\n" - "uniform int layerId\n;" - "uniform sampler2D layer;\n" - "uniform sampler2D layerFlags;\n" - "uniform sampler2D oldLayer;\n" - "uniform sampler2D oldLayerFlags;\n" - "uniform sampler2D oldOldFlags;\n" - "uniform sampler2D window;\n" - "out vec4 color;\n" - "out vec4 flags;\n" - "out vec4 oldColor;\n" - "out vec4 oldFlags;\n" - "const vec4 flagCoeff = vec4(32., 32., 16., 16.);\n" - - "void main() {\n" - " vec4 pix = texelFetch(layer, ivec2(texCoord * scale), 0);\n" - " if (pix.a == 0) {\n" - " discard;\n" - " }\n" - " ivec2 windowFlags = ivec2(texelFetch(window, ivec2(texCoord * scale), 0).xy * 32.);\n" - " if (((windowFlags.x | (windowFlags.y << 4)) & layerId) != 0) {\n" - " discard;\n" - " }\n" - " ivec4 inflags = ivec4(texelFetch(layerFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" - " ivec4 oflags = ivec4(texelFetch(oldLayerFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" - " if ((windowFlags.y & 2) != 0) {\n" - " inflags.y = 0;\n" - " }\n" - " if (inflags.x >= oflags.x) {\n" - " ivec4 ooflags = ivec4(texelFetch(oldOldFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" - " if (inflags.x >= ooflags.x) {\n" - " discard;\n" - " }\n" - " oldFlags = inflags / flagCoeff;\n" - " flags = oflags / flagCoeff;\n" - " oldColor = pix;\n" - " color = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" - " } else {\n" - " color = pix;\n" - " oldColor = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" - " flags = inflags / flagCoeff;\n" - " oldFlags = oflags / flagCoeff;\n" - " }\n" - "}"; - static const struct GBAVideoGLUniform _uniformsFinalize[] = { { "loc", GBA_GL_VS_LOC, }, { "maxPos", GBA_GL_VS_MAXPOS, }, { "scale", GBA_GL_FINALIZE_SCALE, }, - { "layer", GBA_GL_FINALIZE_LAYER, }, - { "layerFlags", GBA_GL_FINALIZE_LAYERFLAGS, }, - { "oldLayer", GBA_GL_FINALIZE_OLDLAYER, }, - { "oldFlags", GBA_GL_FINALIZE_OLDFLAGS, }, + { "layers", GBA_GL_FINALIZE_LAYERS, }, + { "flags", GBA_GL_FINALIZE_FLAGS, }, + { "window", GBA_GL_FINALIZE_WINDOW, }, + { "backdrop", GBA_GL_FINALIZE_BACKDROP, }, + { "backdropFlags", GBA_GL_FINALIZE_BACKDROPFLAGS, }, { 0 } }; static const char* const _finalize = "in vec2 texCoord;\n" "uniform int scale;\n" - "uniform sampler2D layer;\n" - "uniform sampler2D layerFlags;\n" - "uniform sampler2D oldLayer;\n" - "uniform sampler2D oldFlags;\n" + "uniform sampler2D layers[5];\n" + "uniform sampler2D flags[5];\n" + "uniform sampler2D window;\n" + "uniform vec4 backdrop;\n" + "uniform vec4 backdropFlags;\n" "const vec4 flagCoeff = vec4(32., 32., 16., 16.);\n" "out vec4 color;\n" - "void main() {\n" - " vec4 pix = texelFetch(layer, ivec2(texCoord * scale), 0);\n" - " ivec4 inflags = ivec4(texelFetch(layerFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" - " if ((inflags.y & 13) == 5) {\n" - " ivec4 oflags = ivec4(texelFetch(oldFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" - " if ((oflags.y & 2) == 2) {\n" - " vec4 oldpix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n" - " pix *= inflags.z / 16.;\n" - " pix += oldpix * oflags.w / 16.;\n" - " }\n" - " } else if ((inflags.y & 13) == 9) {\n" - " pix += (1. - pix) * inflags.z / 16.;\n" - " } else if ((inflags.y & 13) == 13) {\n" - " pix -= pix * inflags.z / 16.;\n" + "void composite(vec4 pixel, ivec4 flags, inout vec4 topPixel, inout ivec4 topFlags, inout vec4 bottomPixel, inout ivec4 bottomFlags) {\n" + " if (pixel.a == 0) {\n" + " return;\n" " }\n" - " color = pix;\n" + " if (flags.x >= topFlags.x) {\n" + " if (flags.x >= bottomFlags.x) {\n" + " return;\n" + " }\n" + " bottomFlags = flags;\n" + " bottomPixel = pixel;\n" + " } else {\n" + " bottomFlags = topFlags;\n" + " topFlags = flags;\n" + " bottomPixel = topPixel;\n" + " topPixel = pixel;\n" + " }\n" + "}\n" + + "void main() {\n" + " ivec2 windowFlags = ivec2(texelFetch(window, ivec2(texCoord * scale), 0).xy * 32);\n" + " int layerWindow = windowFlags.x | (windowFlags.y << 4);\n" + " vec4 topPixel = backdrop;\n" + " vec4 bottomPixel = backdrop;\n" + " ivec4 topFlags = ivec4(backdropFlags * flagCoeff);\n" + " ivec4 bottomFlags = ivec4(backdropFlags * flagCoeff);\n" + " if ((layerWindow & 16) == 0) {\n" + " vec4 pix = texelFetch(layers[4], ivec2(texCoord * scale), 0);\n" + " ivec4 inflags = ivec4(texelFetch(flags[4], ivec2(texCoord * scale), 0) * flagCoeff);\n" + " composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n" + " }\n" + " if ((layerWindow & 1) == 0) {\n" + " vec4 pix = texelFetch(layers[0], ivec2(texCoord * scale), 0);\n" + " ivec4 inflags = ivec4(texelFetch(flags[0], ivec2(texCoord * scale), 0) * flagCoeff);\n" + " composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n" + " }\n" + " if ((layerWindow & 2) == 0) {\n" + " vec4 pix = texelFetch(layers[1], ivec2(texCoord * scale), 0);\n" + " ivec4 inflags = ivec4(texelFetch(flags[1], ivec2(texCoord * scale), 0) * flagCoeff);\n" + " composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n" + " }\n" + " if ((layerWindow & 4) == 0) {\n" + " vec4 pix = texelFetch(layers[2], ivec2(texCoord * scale), 0);\n" + " ivec4 inflags = ivec4(texelFetch(flags[2], ivec2(texCoord * scale), 0) * flagCoeff);\n" + " composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n" + " }\n" + " if ((layerWindow & 8) == 0) {\n" + " vec4 pix = texelFetch(layers[3], ivec2(texCoord * scale), 0);\n" + " ivec4 inflags = ivec4(texelFetch(flags[3], ivec2(texCoord * scale), 0) * flagCoeff);\n" + " composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n" + " }\n" + " if ((layerWindow & 32) != 0) {\n" + " topFlags.y = 0;\n" + " }\n" + " if ((topFlags.y & 13) == 5) {\n" + " if ((bottomFlags.y & 2) == 2) {\n" + " topPixel *= topFlags.z / 16.;\n" + " topPixel += bottomPixel * bottomFlags.w / 16.;\n" + " }\n" + " } else if ((topFlags.y & 13) == 9) {\n" + " topPixel += (1. - topPixel) * topFlags.z / 16.;\n" + " } else if ((topFlags.y & 13) == 13) {\n" + " topPixel -= topPixel * topFlags.z / 16.;\n" + " }\n" + " color = topPixel;\n" "}"; static const GLint _vertices[] = { @@ -465,12 +453,6 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale); _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], GL_RGBA, GL_COLOR_ATTACHMENT1, glRenderer->scale); - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]); - _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_COMPOSITE_COLOR], GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale); - _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS], GL_RGBA, GL_COLOR_ATTACHMENT1, glRenderer->scale); - _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_COMPOSITE_OLD_COLOR], GL_RGBA, GL_COLOR_ATTACHMENT2, glRenderer->scale); - _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_COMPOSITE_OLD_FLAGS], GL_RGBA, GL_COLOR_ATTACHMENT3, glRenderer->scale); - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_WINDOW]); _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_WINDOW], GL_RG, GL_COLOR_ATTACHMENT0, glRenderer->scale); @@ -559,13 +541,6 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glBindFragDataLocation(glRenderer->objShader[1].program, 2, "window"); #endif - shaderBuffer[1] = _composite; - _compileShader(glRenderer, &glRenderer->compositeShader, shaderBuffer, 2, vs, _uniformsComposite, log); -#ifndef BUILD_GLES3 - glBindFragDataLocation(glRenderer->compositeShader.program, 2, "oldColor"); - glBindFragDataLocation(glRenderer->compositeShader.program, 3, "oldFlags"); -#endif - shaderBuffer[1] = _finalize; _compileShader(glRenderer, &glRenderer->finalizeShader, shaderBuffer, 2, vs, _uniformsFinalize, log); @@ -836,20 +811,8 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } glRenderer->vramDirty = 0; - uint32_t backdrop = M_RGB5_TO_RGB8(renderer->palette[0]); - glClearColor(((backdrop >> 16) & 0xFF) / 256., ((backdrop >> 8) & 0xFF) / 256., (backdrop & 0xFF) / 256., 0.f); - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]); - glEnable(GL_SCISSOR_TEST); - glScissor(0, y * glRenderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, glRenderer->scale); - glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); - glClear(GL_COLOR_BUFFER_BIT); if (y == 0) { - glDisable(GL_SCISSOR_TEST); - glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT1 }); - glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2) | (glRenderer->blendEffect * 4)) / 32.f, - (glRenderer->blendEffect == BLEND_ALPHA ? glRenderer->blda : glRenderer->bldy) / 16.f, glRenderer->bldb / 16.f); - glClear(GL_COLOR_BUFFER_BIT); - + glDisable(GL_SCISSOR_TEST); glClearColor(0, 0, 0, 0); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT3 }); glClear(GL_COLOR_BUFFER_BIT); @@ -902,44 +865,40 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { } } - _compositeLayer(glRenderer, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], 4, y); - unsigned priority; - for (priority = 4; priority--;) { - if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) { - GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[0], y); + if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) { + GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[0], y); + } + if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) { + GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[1], y); + } + if (TEST_LAYER_ENABLED(2)) { + switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) { + case 0: + GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[2], y); + break; + case 1: + case 2: + GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[2], y); + break; + case 3: + //GBAVideoGLRendererDrawBackgroundMode3(glRenderer, &glRenderer->bg[2], y); + break; + case 4: + //GBAVideoGLRendererDrawBackgroundMode4(glRenderer, &glRenderer->bg[2], y); + break; + case 5: + //GBAVideoGLRendererDrawBackgroundMode5(glRenderer, &glRenderer->bg[2], y); + break; } - if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) { - GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[1], y); - } - if (TEST_LAYER_ENABLED(2)) { - switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) { - case 0: - GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[2], y); - break; - case 1: - case 2: - GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[2], y); - break; - case 3: - //GBAVideoGLRendererDrawBackgroundMode3(glRenderer, &glRenderer->bg[2], y); - break; - case 4: - //GBAVideoGLRendererDrawBackgroundMode4(glRenderer, &glRenderer->bg[2], y); - break; - case 5: - //GBAVideoGLRendererDrawBackgroundMode5(glRenderer, &glRenderer->bg[2], y); - break; - } - } - if (TEST_LAYER_ENABLED(3)) { - switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) { - case 0: - GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[3], y); - break; - case 2: - GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[3], y); - break; - } + } + if (TEST_LAYER_ENABLED(3)) { + switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) { + case 0: + GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[3], y); + break; + case 2: + GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[3], y); + break; } } _finalizeLayers(glRenderer, y); @@ -1050,69 +1009,46 @@ static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, u renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value); } -static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int id, int y) { - if ((y & 0x1F) != 0x1F) { - return; - } - const GLuint* uniforms = renderer->compositeShader.uniforms; - glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_COMPOSITE]); - glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); - glScissor(0, (y & ~0x1F) * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale); - glUseProgram(renderer->compositeShader.program); - glBindVertexArray(renderer->compositeShader.vao); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, tex); - glActiveTexture(GL_TEXTURE0 + 1); - glBindTexture(GL_TEXTURE_2D, flags); - glActiveTexture(GL_TEXTURE0 + 2); - glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_COLOR]); - glActiveTexture(GL_TEXTURE0 + 3); - glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]); - glActiveTexture(GL_TEXTURE0 + 4); - glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_OLD_FLAGS]); - glActiveTexture(GL_TEXTURE0 + 5); - glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_WINDOW]); - glUniform2i(uniforms[GBA_GL_VS_LOC], 0x20, y & ~0x1F); - glUniform2i(uniforms[GBA_GL_VS_MAXPOS], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); - glUniform1i(uniforms[GBA_GL_COMPOSITE_SCALE], renderer->scale); - glUniform1i(uniforms[GBA_GL_COMPOSITE_LAYERID], 1 << id); - glUniform1i(uniforms[GBA_GL_COMPOSITE_LAYER], 0); - glUniform1i(uniforms[GBA_GL_COMPOSITE_LAYERFLAGS], 1); - glUniform1i(uniforms[GBA_GL_COMPOSITE_OLDLAYER], 2); - glUniform1i(uniforms[GBA_GL_COMPOSITE_OLDLAYERFLAGS], 3); - glUniform1i(uniforms[GBA_GL_COMPOSITE_OLDOLDFLAGS], 4); - glUniform1i(uniforms[GBA_GL_COMPOSITE_WINDOW], 5); - glDrawBuffers(4, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 }); - glEnableVertexAttribArray(0); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); -} - void _finalizeLayers(struct GBAVideoGLRenderer* renderer, int y) { - if ((y & 0x1F) != 0x1F) { - return; - } const GLuint* uniforms = renderer->finalizeShader.uniforms; glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OUTPUT]); glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale); - glScissor(0, (y & ~0x1F) * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale); + glScissor(0, y * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale); glUseProgram(renderer->finalizeShader.program); glBindVertexArray(renderer->finalizeShader.vao); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_COLOR]); + glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_WINDOW]); glActiveTexture(GL_TEXTURE0 + 1); - glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]); + glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_OBJ_COLOR]); glActiveTexture(GL_TEXTURE0 + 2); - glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_OLD_COLOR]); + glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_OBJ_FLAGS]); glActiveTexture(GL_TEXTURE0 + 3); - glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_OLD_FLAGS]); - glUniform2i(uniforms[GBA_GL_VS_LOC], 0x20, y & ~0x1F); + glBindTexture(GL_TEXTURE_2D, renderer->bg[0].tex); + glActiveTexture(GL_TEXTURE0 + 4); + glBindTexture(GL_TEXTURE_2D, renderer->bg[0].flags); + glActiveTexture(GL_TEXTURE0 + 5); + glBindTexture(GL_TEXTURE_2D, renderer->bg[1].tex); + glActiveTexture(GL_TEXTURE0 + 6); + glBindTexture(GL_TEXTURE_2D, renderer->bg[1].flags); + glActiveTexture(GL_TEXTURE0 + 7); + glBindTexture(GL_TEXTURE_2D, renderer->bg[2].tex); + glActiveTexture(GL_TEXTURE0 + 8); + glBindTexture(GL_TEXTURE_2D, renderer->bg[2].flags); + glActiveTexture(GL_TEXTURE0 + 9); + glBindTexture(GL_TEXTURE_2D, renderer->bg[3].tex); + glActiveTexture(GL_TEXTURE0 + 10); + glBindTexture(GL_TEXTURE_2D, renderer->bg[3].flags); + + uint32_t backdrop = M_RGB5_TO_RGB8(renderer->d.palette[0]); + glUniform2i(uniforms[GBA_GL_VS_LOC], 1, y); glUniform2i(uniforms[GBA_GL_VS_MAXPOS], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); glUniform1i(uniforms[GBA_GL_FINALIZE_SCALE], renderer->scale); - glUniform1i(uniforms[GBA_GL_FINALIZE_LAYER], 0); - glUniform1i(uniforms[GBA_GL_FINALIZE_LAYERFLAGS], 1); - glUniform1i(uniforms[GBA_GL_FINALIZE_OLDLAYER], 2); - glUniform1i(uniforms[GBA_GL_FINALIZE_OLDFLAGS], 3); + glUniform1iv(uniforms[GBA_GL_FINALIZE_LAYERS], 5, (GLint[]) { 3, 5, 7, 9, 1 }); + glUniform1iv(uniforms[GBA_GL_FINALIZE_FLAGS], 5, (GLint[]) { 4, 6, 8, 10, 2 }); + glUniform1i(uniforms[GBA_GL_FINALIZE_WINDOW], 0); + glUniform4f(uniforms[GBA_GL_FINALIZE_BACKDROP], ((backdrop >> 16) & 0xFF) / 256., ((backdrop >> 8) & 0xFF) / 256., (backdrop & 0xFF) / 256., 0.f); + glUniform4f(uniforms[GBA_GL_FINALIZE_BACKDROPFLAGS], 1, (renderer->target1Bd | (renderer->target2Bd * 2) | (renderer->blendEffect * 4)) / 32.f, + (renderer->blendEffect == BLEND_ALPHA ? renderer->blda : renderer->bldy) / 16.f, renderer->bldb / 16.f); glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -1226,8 +1162,6 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); - - _compositeLayer(renderer, background->tex, background->flags, background->index, y); } void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) { @@ -1283,8 +1217,6 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); - - _compositeLayer(renderer, background->tex, background->flags, background->index, y); } static void _clearWindow(GBAWindowControl window, int start, int end, int y, int scale) { @@ -1296,18 +1228,18 @@ static void _clearWindow(GBAWindowControl window, int start, int end, int y, int void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y) { glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_WINDOW]); + int dispcnt = ((renderer->dispcnt >> 8) & 0x1F) | 0x20; if (!(renderer->dispcnt & 0xE000)) { - _clearWindow(0xFF, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, y * renderer->scale, renderer->scale); + _clearWindow(dispcnt, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, y * renderer->scale, renderer->scale); } else { - _clearWindow(renderer->winout, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, y * renderer->scale, renderer->scale); + _clearWindow(renderer->winout & dispcnt, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, y * renderer->scale, renderer->scale); if (GBARegisterDISPCNTIsWin1Enable(renderer->dispcnt) && y >= renderer->winN[1].v.start && y < renderer->winN[1].v.end) { - _clearWindow(renderer->winN[1].control, renderer->winN[1].h.start * renderer->scale, renderer->winN[1].h.end * renderer->scale, y * renderer->scale, renderer->scale); + _clearWindow(renderer->winN[1].control & dispcnt, renderer->winN[1].h.start * renderer->scale, renderer->winN[1].h.end * renderer->scale, y * renderer->scale, renderer->scale); } if (GBARegisterDISPCNTIsWin0Enable(renderer->dispcnt) && y >= renderer->winN[0].v.start && y < renderer->winN[0].v.end) { - _clearWindow(renderer->winN[0].control, renderer->winN[0].h.start * renderer->scale, renderer->winN[0].h.end * renderer->scale, y * renderer->scale, renderer->scale); + _clearWindow(renderer->winN[0].control & dispcnt, renderer->winN[0].h.start * renderer->scale, renderer->winN[0].h.end * renderer->scale, y * renderer->scale, renderer->scale); } } - glBindFramebuffer(GL_FRAMEBUFFER, 0); } #endif From b92a08e6f1fddee946c93030fceab0af83aea7a0 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 15 May 2019 23:43:20 -0700 Subject: [PATCH 41/44] OpenGL: Reset clear color as needed --- src/platform/opengl/gles2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/opengl/gles2.c b/src/platform/opengl/gles2.c index 465820528..35e7ac9e0 100644 --- a/src/platform/opengl/gles2.c +++ b/src/platform/opengl/gles2.c @@ -88,8 +88,6 @@ static void mGLES2ContextInit(struct VideoBackend* v, WHandle handle) { glBindBuffer(GL_ARRAY_BUFFER, context->vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(_vertices), _vertices, GL_STATIC_DRAW); - glClearColor(0.f, 0.f, 0.f, 1.f); - struct mGLES2Uniform* uniforms = malloc(sizeof(struct mGLES2Uniform) * 4); uniforms[0].name = "gamma"; uniforms[0].readableName = "Gamma"; @@ -236,6 +234,7 @@ void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { glDisable(GL_BLEND); + glClearColor(0.f, 0.f, 0.f, 1.f); glClear(GL_COLOR_BUFFER_BIT); } @@ -459,6 +458,7 @@ void mGLES2ShaderAttach(struct mGLES2Context* context, struct mGLES2Shader* shad size_t i; for (i = 0; i < nShaders; ++i) { glBindFramebuffer(GL_FRAMEBUFFER, context->shaders[i].fbo); + glClearColor(0.f, 0.f, 0.f, 1.f); glClear(GL_COLOR_BUFFER_BIT); glBindVertexArray(context->shaders[i].vao); From ac7ae74822d2740f82b62a644e88fbed789ad2be Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 16 May 2019 09:59:49 -0700 Subject: [PATCH 42/44] GBA Video: Fix GL sprite window blending --- src/gba/renderers/gl.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 1aa811485..9527ef2a9 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -317,11 +317,6 @@ static const char* const _finalize = " vec4 bottomPixel = backdrop;\n" " ivec4 topFlags = ivec4(backdropFlags * flagCoeff);\n" " ivec4 bottomFlags = ivec4(backdropFlags * flagCoeff);\n" - " if ((layerWindow & 16) == 0) {\n" - " vec4 pix = texelFetch(layers[4], ivec2(texCoord * scale), 0);\n" - " ivec4 inflags = ivec4(texelFetch(flags[4], ivec2(texCoord * scale), 0) * flagCoeff);\n" - " composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n" - " }\n" " if ((layerWindow & 1) == 0) {\n" " vec4 pix = texelFetch(layers[0], ivec2(texCoord * scale), 0);\n" " ivec4 inflags = ivec4(texelFetch(flags[0], ivec2(texCoord * scale), 0) * flagCoeff);\n" @@ -343,7 +338,12 @@ static const char* const _finalize = " composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n" " }\n" " if ((layerWindow & 32) != 0) {\n" - " topFlags.y = 0;\n" + " topFlags.y &= ~1;\n" + " }\n" + " if ((layerWindow & 16) == 0) {\n" + " vec4 pix = texelFetch(layers[4], ivec2(texCoord * scale), 0);\n" + " ivec4 inflags = ivec4(texelFetch(flags[4], ivec2(texCoord * scale), 0) * flagCoeff);\n" + " composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n" " }\n" " if ((topFlags.y & 13) == 5) {\n" " if ((bottomFlags.y & 2) == 2) {\n" @@ -827,9 +827,8 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { glClear(GL_COLOR_BUFFER_BIT); } glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); - glEnable(GL_SCISSOR_TEST); } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glEnable(GL_SCISSOR_TEST); if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) { if (glRenderer->firstAffine < 0) { From 8a26a7977c0dea8315ea9b1a6df9df7da27b1fe5 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 16 May 2019 17:09:50 -0700 Subject: [PATCH 43/44] GBA Video: GL screenshots --- include/mgba/feature/video-logger.h | 4 ++++ include/mgba/internal/gba/renderers/gl.h | 2 ++ src/gb/extra/proxy.c | 10 ++++++---- src/gba/core.c | 8 ++++---- src/gba/extra/proxy.c | 12 +++++++++--- src/gba/renderers/gl.c | 17 ++++++++++++++++- 6 files changed, 41 insertions(+), 12 deletions(-) diff --git a/include/mgba/feature/video-logger.h b/include/mgba/feature/video-logger.h index bae94157a..d33e83155 100644 --- a/include/mgba/feature/video-logger.h +++ b/include/mgba/feature/video-logger.h @@ -32,6 +32,7 @@ enum mVideoLoggerEvent { LOGGER_EVENT_INIT, LOGGER_EVENT_DEINIT, LOGGER_EVENT_RESET, + LOGGER_EVENT_GET_PIXELS, }; struct mVideoLoggerDirtyInfo { @@ -73,6 +74,9 @@ struct mVideoLogger { uint16_t* vram; uint16_t* oam; uint16_t* palette; + + const void* pixelBuffer; + size_t pixelStride; }; void mVideoLoggerRendererCreate(struct mVideoLogger* logger, bool readonly); diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index 4b1c4a07f..209607f1c 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -121,6 +121,8 @@ struct GBAVideoGLShader { struct GBAVideoGLRenderer { struct GBAVideoRenderer d; + uint32_t* temporaryBuffer; + struct GBAVideoGLBackground bg[4]; int oamMax; diff --git a/src/gb/extra/proxy.c b/src/gb/extra/proxy.c index c5230c88c..d8538124d 100644 --- a/src/gb/extra/proxy.c +++ b/src/gb/extra/proxy.c @@ -283,11 +283,13 @@ static void GBVideoProxyRendererGetPixels(struct GBVideoRenderer* renderer, size proxyRenderer->logger->lock(proxyRenderer->logger); // Insert an extra item into the queue to make sure it gets flushed mVideoLoggerRendererFlush(proxyRenderer->logger); - proxyRenderer->logger->wait(proxyRenderer->logger); - } - proxyRenderer->backend->getPixels(proxyRenderer->backend, stride, pixels); - if (proxyRenderer->logger->block && proxyRenderer->logger->wait) { + proxyRenderer->logger->postEvent(proxyRenderer->logger, LOGGER_EVENT_GET_PIXELS); + mVideoLoggerRendererFlush(proxyRenderer->logger); proxyRenderer->logger->unlock(proxyRenderer->logger); + *pixels = proxyRenderer->logger->pixelBuffer; + *stride = proxyRenderer->logger->pixelStride; + } else { + proxyRenderer->backend->getPixels(proxyRenderer->backend, stride, pixels); } } diff --git a/src/gba/core.c b/src/gba/core.c index 839404d03..0fc449972 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -310,13 +310,13 @@ static void _GBACoreSetVideoGLTex(struct mCore* core, unsigned texid) { } static void _GBACoreGetPixels(struct mCore* core, const void** buffer, size_t* stride) { - struct GBACore* gbacore = (struct GBACore*) core; - gbacore->renderer.d.getPixels(&gbacore->renderer.d, stride, buffer); + struct GBA* gba = core->board; + gba->video.renderer->getPixels(gba->video.renderer, stride, buffer); } static void _GBACorePutPixels(struct mCore* core, const void* buffer, size_t stride) { - struct GBACore* gbacore = (struct GBACore*) core; - gbacore->renderer.d.putPixels(&gbacore->renderer.d, stride, buffer); + struct GBA* gba = core->board; + gba->video.renderer->putPixels(gba->video.renderer, stride, buffer); } static struct blip_t* _GBACoreGetAudioChannel(struct mCore* core, int ch) { diff --git a/src/gba/extra/proxy.c b/src/gba/extra/proxy.c index 38bfb4514..bd90f1271 100644 --- a/src/gba/extra/proxy.c +++ b/src/gba/extra/proxy.c @@ -152,6 +152,9 @@ static void _handleEvent(struct mVideoLogger* logger, enum mVideoLoggerEvent eve case LOGGER_EVENT_RESET: proxyRenderer->backend->reset(proxyRenderer->backend); break; + case LOGGER_EVENT_GET_PIXELS: + proxyRenderer->backend->getPixels(proxyRenderer->backend, &logger->pixelStride, &logger->pixelBuffer); + break; } } @@ -305,10 +308,13 @@ static void GBAVideoProxyRendererGetPixels(struct GBAVideoRenderer* renderer, si proxyRenderer->logger->lock(proxyRenderer->logger); // Insert an extra item into the queue to make sure it gets flushed mVideoLoggerRendererFlush(proxyRenderer->logger); - } - proxyRenderer->backend->getPixels(proxyRenderer->backend, stride, pixels); - if (proxyRenderer->logger->block && proxyRenderer->logger->wait) { + proxyRenderer->logger->postEvent(proxyRenderer->logger, LOGGER_EVENT_GET_PIXELS); + mVideoLoggerRendererFlush(proxyRenderer->logger); proxyRenderer->logger->unlock(proxyRenderer->logger); + *pixels = proxyRenderer->logger->pixelBuffer; + *stride = proxyRenderer->logger->pixelStride; + } else { + proxyRenderer->backend->getPixels(proxyRenderer->backend, stride, pixels); } } diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 9527ef2a9..c5a069738 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -11,6 +11,7 @@ #include #include #include +#include static void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer); static void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer); @@ -435,6 +436,8 @@ static void _initFramebufferTexture(GLuint tex, GLenum format, GLenum attachment void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + glRenderer->temporaryBuffer = NULL; + glGenFramebuffers(GBA_GL_FBO_MAX, glRenderer->fbo); glGenTextures(GBA_GL_TEX_MAX, glRenderer->layers); @@ -552,6 +555,9 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + if (glRenderer->temporaryBuffer) { + mappedMemoryFree(glRenderer->temporaryBuffer, GBA_VIDEO_HORIZONTAL_PIXELS * GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale * glRenderer->scale); + } glDeleteFramebuffers(GBA_GL_FBO_MAX, glRenderer->fbo); glDeleteTextures(GBA_GL_TEX_MAX, glRenderer->layers); glDeleteTextures(1, &glRenderer->paletteTex); @@ -928,7 +934,16 @@ void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) { } void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) { - + struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + *stride = GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale; + if (!glRenderer->temporaryBuffer) { + glRenderer->temporaryBuffer = anonymousMemoryMap(GBA_VIDEO_HORIZONTAL_PIXELS * GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale * glRenderer->scale * BYTES_PER_PIXEL); + } + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OUTPUT]); + glPixelStorei(GL_PACK_ROW_LENGTH, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, GL_RGBA, GL_UNSIGNED_BYTE, (void*) glRenderer->temporaryBuffer); + *pixels = glRenderer->temporaryBuffer; } void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) { From c40217fc8e6a98885a7a272566e892ff1462bdba Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 17 May 2019 14:40:16 -0700 Subject: [PATCH 44/44] GBA: Fix hi-res videos --- src/gba/core.c | 4 +++- src/gba/renderers/gl.c | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gba/core.c b/src/gba/core.c index 0fc449972..44d125f73 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -355,7 +355,9 @@ static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) { struct GBA* gba = core->board; gba->stream = stream; if (stream && stream->videoDimensionsChanged) { - stream->videoDimensionsChanged(stream, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + stream->videoDimensionsChanged(stream, width, height); } } diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index c5a069738..81fc5cdb8 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -820,9 +820,6 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { if (y == 0) { glDisable(GL_SCISSOR_TEST); glClearColor(0, 0, 0, 0); - glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT3 }); - glClear(GL_COLOR_BUFFER_BIT); - glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]); glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); glClear(GL_COLOR_BUFFER_BIT); @@ -939,6 +936,7 @@ void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stri if (!glRenderer->temporaryBuffer) { glRenderer->temporaryBuffer = anonymousMemoryMap(GBA_VIDEO_HORIZONTAL_PIXELS * GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale * glRenderer->scale * BYTES_PER_PIXEL); } + glFinish(); glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OUTPUT]); glPixelStorei(GL_PACK_ROW_LENGTH, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale); glPixelStorei(GL_PACK_ALIGNMENT, 1);