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