all repos — mgba @ 8450417086c5b70904f93f2db720456d54c9cfeb

mGBA Game Boy Advance Emulator

Core: Improve OpenGL integration, update Qt to use improvements
Vicki Pfau vi@endrift.com
Tue, 14 May 2019 13:02:36 -0700
commit

8450417086c5b70904f93f2db720456d54c9cfeb

parent

49a9da3e5ca5e414d58a2f15920d1349c01124c4

M CMakeLists.txtCMakeLists.txt

@@ -57,7 +57,7 @@ set(BUILD_STATIC OFF CACHE BOOL "Build a static library")

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 @@ set(BUILD_GL OFF CACHE BOOL "OpenGL not found" FORCE)

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)

@@ -473,6 +473,16 @@ endif()

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)

@@ -733,6 +743,10 @@ include_directories(AFTER ${EPOXY_INCLUDE_DIRS})

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)
M include/mgba/core/core.hinclude/mgba/core/core.h

@@ -64,6 +64,7 @@ bool (*init)(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*);
M include/mgba/core/interface.hinclude/mgba/core/interface.h

@@ -80,6 +80,10 @@

mCOLOR_ANY = -1 }; +enum mCoreFeature { + mCORE_FEATURE_OPENGL = 1, +}; + struct mCoreCallbacks { void* context; void (*videoFrameStarted)(void* context);
M include/mgba/internal/gba/renderers/gl.hinclude/mgba/internal/gba/renderers/gl.h

@@ -16,6 +16,8 @@ #include <mgba/internal/gba/io.h>

#include <mgba/internal/gba/renderers/common.h> #include <mgba/internal/gba/video.h> +#if defined(BUILD_GLES2) || defined(BUILD_GLES3) + #ifdef USE_EPOXY #include <epoxy/gl.h> #elif defined(BUILD_GL)

@@ -27,7 +29,7 @@ #include <GL/gl.h>

#include <GL/glext.h> #endif #else -#include <GLES2/gl2.h> +#include <GLES3/gl3.h> #endif struct GBAVideoGLAffine {

@@ -137,6 +139,9 @@ GLuint layers[GBA_GL_TEX_MAX];

GLuint outputTex; +#ifdef BUILD_GLES3 + uint16_t shadowPalette[512]; +#endif GLuint paletteTex; bool paletteDirty;

@@ -181,6 +186,8 @@ int scale;

}; void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer); + +#endif CXX_GUARD_END
M src/gb/core.csrc/gb/core.c

@@ -138,6 +138,14 @@ UNUSED(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 @@ core->symbolTable = NULL;

core->init = _GBCoreInit; core->deinit = _GBCoreDeinit; core->platform = _GBCorePlatform; + core->supportsFeature = _GBCoreSupportsFeature; core->setSync = _GBCoreSetSync; core->loadConfig = _GBCoreLoadConfig; core->desiredVideoDimensions = _GBCoreDesiredVideoDimensions;
M src/gba/core.csrc/gba/core.c

@@ -17,7 +17,9 @@ #include <mgba/internal/gba/overrides.h>

#ifndef DISABLE_THREADING #include <mgba/feature/thread-proxy.h> #endif +#ifdef BUILD_GLES2 #include <mgba/internal/gba/renderers/gl.h> +#endif #include <mgba/internal/gba/renderers/proxy.h> #include <mgba/internal/gba/renderers/video-software.h> #include <mgba/internal/gba/savedata.h>

@@ -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 @@

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 @@ UNUSED(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 @@ mCoreConfigCopyValue(&core->config, config, "videoScale");

} 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 @@ memset(gbacore->renderer.scanlineDirty, 0xFFFFFFFF, sizeof(gbacore->renderer.scanlineDirty));

} 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 _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 @@ core->debugger = NULL;

core->init = _GBACoreInit; core->deinit = _GBACoreDeinit; core->platform = _GBACorePlatform; + core->supportsFeature = _GBACoreSupportsFeature; core->setSync = _GBACoreSetSync; core->loadConfig = _GBACoreLoadConfig; core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions;
M src/gba/renderers/gl.csrc/gba/renderers/gl.c

@@ -5,6 +5,8 @@ * 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 <mgba/internal/gba/renderers/gl.h> +#if defined(BUILD_GLES2) || defined(BUILD_GLES3) + #include <mgba/core/cache-set.h> #include <mgba/internal/arm/macros.h> #include <mgba/internal/gba/io.h>

@@ -90,7 +92,7 @@ " color.a = 1.;\n"

" 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 @@ " }\n"

" 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 @@ " color = fetchTile(ivec2(mixedTransform * texCoord.x + mixedOffset));\n"

" 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 @@ " flags = inflags / flagCoeff;\n"

" 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 @@ " oldFlags = oflags / flagCoeff;\n"

" }\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 @@ if (log[0]) {

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 @@

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 @@ 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->compositeProgram);

@@ -611,9 +620,13 @@ glRenderer->oamDirty = true;

} 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 @@ 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); - 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 @@ }

} glBindFramebuffer(GL_FRAMEBUFFER, 0); } + +#endif
M src/platform/qt/CMakeLists.txtsrc/platform/qt/CMakeLists.txt

@@ -47,17 +47,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")

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 @@ else()

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}/res/mgba.icns ${SOURCE_FILES} ${PLATFORM_SRC} ${UI_SRC} ${AUDIO_SRC} ${RESOURCES})

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)
M src/platform/qt/CoreController.cppsrc/platform/qt/CoreController.cpp

@@ -40,16 +40,6 @@ {

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<color_t*>(m_activeBuffer->data()), size.width()); - m_resetActions.append([this]() { if (m_autoload) { mCoreLoadState(m_threadContext.core, 0, m_loadStateFlags);

@@ -91,8 +81,10 @@ }

controller->m_resetActions.clear(); - controller->m_activeBuffer = &controller->m_buffers[0]; - context->core->setVideoBuffer(context->core, reinterpret_cast<color_t*>(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<color_t*>(controller->m_activeBuffer->data()), controller->screenDimensions().width()); + } controller->finishFrame(); };

@@ -211,6 +203,9 @@ }

const color_t* CoreController::drawContext() { QMutexLocker locker(&m_mutex); + if (m_hwaccel) { + return nullptr; + } return reinterpret_cast<const color_t*>(m_completeBuffer.constData()); }

@@ -340,6 +335,18 @@ connect(this, &CoreController::logPosted, m_log, &LogController::postLog);

} 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<color_t*>(m_activeBuffer->data()), size.width()); + } + if (!m_patched) { mCoreAutoloadPatch(m_threadContext.core); }

@@ -800,6 +807,16 @@ }

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 @@ }

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<color_t*>(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<color_t*>(m_activeBuffer->data()), screenDimensions().width()); - for (auto& action : m_frameActions) { action(); }
M src/platform/qt/CoreController.hsrc/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 @@ bool hasStarted();

mPlatform platform() const; QSize screenDimensions() const; + bool supportsFeature(Feature feature) const { return m_threadContext.core->supportsFeature(m_threadContext.core, static_cast<mCoreFeature>(feature)); } + bool hardwareAccelerated() const { return m_hwaccel; } void loadConfig(ConfigController*);

@@ -154,6 +160,8 @@

void startVideoLog(const QString& path); void endVideoLog(); + void setFramebufferHandle(int fb); + signals: void started(); void paused();

@@ -188,6 +196,7 @@

QByteArray m_buffers[2]; QByteArray* m_activeBuffer; QByteArray m_completeBuffer; + bool m_hwaccel = false; std::unique_ptr<mCacheSet> m_cacheSet; std::unique_ptr<Override> m_override;
M src/platform/qt/Display.hsrc/platform/qt/Display.h

@@ -49,6 +49,7 @@ virtual bool isDrawing() const = 0;

virtual bool supportsShaders() const = 0; virtual VideoShader* shaders() = 0; virtual VideoProxy* videoProxy() { return nullptr; } + virtual int framebufferHandle() { return -1; } signals: void showCursor();
M src/platform/qt/DisplayGL.cppsrc/platform/qt/DisplayGL.cpp

@@ -18,7 +18,7 @@ #include <mgba-util/math.h>

#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 <epoxy/wgl.h>

@@ -195,6 +195,10 @@ }

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 @@ {

#ifdef BUILD_GL mGLContext* glBackend; #endif -#if !defined(_WIN32) || defined(USE_EPOXY) +#ifdef BUILD_GLES2 mGLES2Context* gl2Backend; #endif

@@ -213,7 +217,7 @@ #endif

QStringList extensions = QString(reinterpret_cast<const char*>(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<mGLES2Context*>(malloc(sizeof(mGLES2Context))); mGLES2ContextCreate(gl2Backend);

@@ -239,7 +243,7 @@ painter->m_gl->swapBuffers();

}; m_backend->init(m_backend, reinterpret_cast<WHandle>(m_gl->winId())); -#if !defined(_WIN32) || defined(USE_EPOXY) +#ifdef BUILD_GLES2 if (m_supportsShaders) { m_shader.preprocessShader = static_cast<void*>(&reinterpret_cast<mGLES2Context*>(m_backend)->initialShader); }

@@ -266,7 +270,7 @@ m_gl->makeCurrent();

#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 @@ #if defined(_WIN32) && defined(USE_EPOXY)

epoxy_handle_external_wglMakeCurrent(); #endif -#if !defined(_WIN32) || defined(USE_EPOXY) +#ifdef BUILD_GLES2 if (m_supportsShaders && m_shader.passes) { mGLES2ShaderAttach(reinterpret_cast<mGLES2Context*>(m_backend), static_cast<mGLES2Shader*>(m_shader.passes), m_shader.nPasses); }

@@ -422,14 +426,16 @@ }

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 @@ m_mutex.unlock();

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 @@ uint32_t* buffer = 0;

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 @@ if (!supportsShaders()) {

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 @@ if (!supportsShaders()) {

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();

@@ -507,6 +517,21 @@ }

VideoShader* PainterGL::shaders() { return &m_shader; +} + +int PainterGL::glTex() { +#ifdef BUILD_GLES2 + if (supportsShaders()) { + mGLES2Context* gl2Backend = reinterpret_cast<mGLES2Context*>(m_backend); + return gl2Backend->tex; + } +#endif +#ifdef BUILD_GL + mGLContext* glBackend = reinterpret_cast<mGLContext*>(m_backend); + return glBackend->tex; +#else + return -1; +#endif } #endif
M src/platform/qt/DisplayGL.hsrc/platform/qt/DisplayGL.h

@@ -52,6 +52,7 @@ bool isDrawing() const override { return m_isDrawing; }

bool supportsShaders() const override; VideoShader* shaders() override; VideoProxy* videoProxy() override; + int framebufferHandle() override; public slots: void stopDrawing() override;

@@ -110,6 +111,8 @@

void setShaders(struct VDir*); void clearShaders(); VideoShader* shaders(); + + int glTex(); private: void performDraw();
M src/platform/qt/Window.cppsrc/platform/qt/Window.cpp

@@ -851,6 +851,10 @@ }

void Window::reloadDisplayDriver() { if (m_controller) { + if (m_controller->hardwareAccelerated()) { + mustRestart(); + return; + } m_display->stopDrawing(); detachWidget(m_display.get()); }

@@ -1715,8 +1719,15 @@ if (!m_display) {

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<CoreController>(controller);
M src/platform/sdl/CMakeLists.txtsrc/platform/sdl/CMakeLists.txt

@@ -77,12 +77,11 @@ list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/pandora-sdl.c)

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)
M src/platform/sdl/gles2-sdl.csrc/platform/sdl/gles2-sdl.c

@@ -35,7 +35,9 @@ mSDLGLCommonInit(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);
M tools/sanitize-deb.shtools/sanitize-deb.sh

@@ -31,6 +31,7 @@ PKG=$BINARY-qt

rmdep libav rmdep libedit rmdep libelf + rmdep libgl rmdep libpng rmdep libzip rmdep libmagickwand

@@ -45,6 +46,7 @@ PKG=$BINARY-sdl

rmdep libav rmdep libedit rmdep libelf + rmdep libgl rmdep libpng rmdep qt rmdep libzip