Core: Improve OpenGL integration, update Qt to use improvements
jump to
@@ -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)
@@ -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*);
@@ -80,6 +80,10 @@
mCOLOR_ANY = -1 }; +enum mCoreFeature { + mCORE_FEATURE_OPENGL = 1, +}; + struct mCoreCallbacks { void* context; void (*videoFrameStarted)(void* context);
@@ -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
@@ -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;
@@ -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;
@@ -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
@@ -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)
@@ -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(); }
@@ -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;
@@ -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();
@@ -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
@@ -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();
@@ -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);
@@ -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)
@@ -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);
@@ -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