From ca566eb11b9747e799229751be2d6cd17a34a32f Mon Sep 17 00:00:00 2001 From: rogerman Date: Thu, 1 Aug 2024 17:08:01 -0700 Subject: [PATCH] OpenGL Renderer: Finalize all renderer-client integration to "just work". - These changes now presume that standard OpenGL and OpenGL ES are mutually exclusive. We will NOT support running a standard OpenGL context and an OpenGL ES context in the same process. - Clients must explicitly request supporting the OpenGL 3D renderer in their build configuration. Build configurations must define ENABLE_OPENGL_STANDARD (replacing the HAVE_OPENGL macro) or ENABLE_OPENGL_ES. If neither macro is defined, then the OpenGL 3D renderer will be assumed unavailable. - Meson and Autotools now use better header/library checks for OpenGL functionality with their associated context type. - Add a new Code::Blocks project file that can make builds for CLI, GTK, and GTK2. - GTK and GTK2 ports now have the option to run a legacy OpenGL context, a 3.2 Core Profile context, or simply choosing the best context automatically like before. - GTK and GTK2 ports have GLX and EGL as new context types. OSMesa and SDL have been updated to the latest design pattern. - GTK and GTK2 ports can now be configured (via Meson or Autotools) to use a GLX, OSMesa, EGL, or SDL context. - OSMesa contexts are now marked as deprecated. I don't know of anyone who still uses them, and I've never been able to get it to work correctly for years. Now that we have GLX contexts for compatibility purposes, OSMesa contexts are now completely redundant. - Fix a bug with the GTK port where ancient GPUs without FBO support can still run framebuffers at custom sizes. - For POSIX ports, move all "avout" and context creation files to the "shared" directory for better file organization. --- desmume/src/Makefile.am | 14 +- desmume/src/OGLRender.h | 89 +- .../project.pbxproj | 4 + desmume/src/frontend/cocoa/DeSmuME_Prefix.pch | 4 +- .../cocoa/openemu/DeSmuME_Prefix_OpenEmu.pch | 4 +- desmume/src/frontend/modules/ImageOut.cpp | 4 +- desmume/src/frontend/posix/Makefile.am | 14 +- .../src/frontend/posix/codeblocks/desmume.cbp | 1348 +++++++++++++++++ desmume/src/frontend/posix/configure.ac | 139 +- desmume/src/frontend/posix/gtk/Makefile.am | 41 +- desmume/src/frontend/posix/gtk/graphics.ui | 95 +- desmume/src/frontend/posix/gtk/main.cpp | 296 +++- desmume/src/frontend/posix/gtk/meson.build | 36 +- .../src/frontend/posix/gtk/osmesa_3Demu.cpp | 111 -- desmume/src/frontend/posix/gtk/osmesa_3Demu.h | 27 - desmume/src/frontend/posix/gtk/sdl_3Demu.cpp | 91 -- desmume/src/frontend/posix/gtk/sdl_3Demu.h | 26 - desmume/src/frontend/posix/gtk2/Makefile.am | 41 +- .../src/frontend/posix/gtk2/avout_flac.cpp | 61 - desmume/src/frontend/posix/gtk2/avout_flac.h | 34 - .../frontend/posix/gtk2/avout_pipe_base.cpp | 102 -- .../src/frontend/posix/gtk2/avout_pipe_base.h | 39 - .../src/frontend/posix/gtk2/avout_x264.cpp | 47 - desmume/src/frontend/posix/gtk2/main.cpp | 312 +++- desmume/src/frontend/posix/gtk2/meson.build | 36 +- .../src/frontend/posix/gtk2/osmesa_3Demu.cpp | 111 -- desmume/src/frontend/posix/gtk2/sdl_3Demu.cpp | 87 -- desmume/src/frontend/posix/meson.build | 69 +- desmume/src/frontend/posix/meson_options.txt | 25 + .../frontend/posix/{gtk => shared}/avout.h | 0 .../posix/{gtk => shared}/avout_flac.cpp | 0 .../posix/{gtk => shared}/avout_flac.h | 0 .../posix/{gtk => shared}/avout_pipe_base.cpp | 0 .../posix/{gtk => shared}/avout_pipe_base.h | 0 .../posix/{gtk => shared}/avout_x264.cpp | 0 .../posix/{gtk => shared}/avout_x264.h | 0 .../src/frontend/posix/shared/egl_3Demu.cpp | 357 +++++ .../{gtk2/avout_x264.h => shared/egl_3Demu.h} | 27 +- .../src/frontend/posix/shared/glx_3Demu.cpp | 370 +++++ .../{gtk2/avout.h => shared/glx_3Demu.h} | 24 +- .../frontend/posix/shared/osmesa_3Demu.cpp | 284 ++++ .../posix/{gtk2 => shared}/osmesa_3Demu.h | 23 +- .../src/frontend/posix/shared/sdl_3Demu.cpp | 232 +++ .../posix/{gtk2 => shared}/sdl_3Demu.h | 19 +- 44 files changed, 3567 insertions(+), 1076 deletions(-) create mode 100644 desmume/src/frontend/posix/codeblocks/desmume.cbp delete mode 100644 desmume/src/frontend/posix/gtk/osmesa_3Demu.cpp delete mode 100644 desmume/src/frontend/posix/gtk/osmesa_3Demu.h delete mode 100644 desmume/src/frontend/posix/gtk/sdl_3Demu.cpp delete mode 100644 desmume/src/frontend/posix/gtk/sdl_3Demu.h delete mode 100644 desmume/src/frontend/posix/gtk2/avout_flac.cpp delete mode 100644 desmume/src/frontend/posix/gtk2/avout_flac.h delete mode 100644 desmume/src/frontend/posix/gtk2/avout_pipe_base.cpp delete mode 100644 desmume/src/frontend/posix/gtk2/avout_pipe_base.h delete mode 100644 desmume/src/frontend/posix/gtk2/avout_x264.cpp delete mode 100644 desmume/src/frontend/posix/gtk2/osmesa_3Demu.cpp delete mode 100644 desmume/src/frontend/posix/gtk2/sdl_3Demu.cpp rename desmume/src/frontend/posix/{gtk => shared}/avout.h (100%) rename desmume/src/frontend/posix/{gtk => shared}/avout_flac.cpp (100%) rename desmume/src/frontend/posix/{gtk => shared}/avout_flac.h (100%) rename desmume/src/frontend/posix/{gtk => shared}/avout_pipe_base.cpp (100%) rename desmume/src/frontend/posix/{gtk => shared}/avout_pipe_base.h (100%) rename desmume/src/frontend/posix/{gtk => shared}/avout_x264.cpp (100%) rename desmume/src/frontend/posix/{gtk => shared}/avout_x264.h (100%) create mode 100644 desmume/src/frontend/posix/shared/egl_3Demu.cpp rename desmume/src/frontend/posix/{gtk2/avout_x264.h => shared/egl_3Demu.h} (61%) create mode 100644 desmume/src/frontend/posix/shared/glx_3Demu.cpp rename desmume/src/frontend/posix/{gtk2/avout.h => shared/glx_3Demu.h} (63%) create mode 100644 desmume/src/frontend/posix/shared/osmesa_3Demu.cpp rename desmume/src/frontend/posix/{gtk2 => shared}/osmesa_3Demu.h (68%) create mode 100644 desmume/src/frontend/posix/shared/sdl_3Demu.cpp rename desmume/src/frontend/posix/{gtk2 => shared}/sdl_3Demu.h (68%) diff --git a/desmume/src/Makefile.am b/desmume/src/Makefile.am index b17d4df7f..971611eea 100644 --- a/desmume/src/Makefile.am +++ b/desmume/src/Makefile.am @@ -29,7 +29,6 @@ libdesmume_a_SOURCES = \ wifi.cpp wifi.h \ mic.h \ MMU.cpp MMU.h MMU_timing.h NDSSystem.cpp NDSSystem.h registers.h \ - OGLRender.h OGLRender_3_2.h \ ROMReader.cpp ROMReader.h \ render3D.cpp render3D.h \ rtc.cpp rtc.h \ @@ -230,8 +229,17 @@ libdesmume_a_SOURCES += \ utils/AsmJit/x86/x86util.h endif -if HAVE_GL -libdesmume_a_SOURCES += OGLRender.cpp OGLRender_3_2.cpp +if ENABLE_OPENGL_ES +libdesmume_a_SOURCES += \ + OGLRender.h OGLRender_3_2.h \ + OGLRender.cpp OGLRender_3_2.cpp \ + OGLRender_ES3.h OGLRender_ES3.cpp +else +if ENABLE_OPENGL_STANDARD +libdesmume_a_SOURCES += \ + OGLRender.h OGLRender_3_2.h \ + OGLRender.cpp OGLRender_3_2.cpp +endif endif if HAVE_OPENAL diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index ffdd160bb..4c207ea47 100644 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -27,29 +27,15 @@ #include "render3D.h" #include "types.h" -// OPENGL PLATFORM-SPECIFIC INCLUDES -#if defined(__ANGLE__) || defined(__ANDROID__) - #define OPENGL_VARIANT_ES - #define _NO_SDL_TYPES - #include - #define __gles2_gl2_h_ // Guard against including the gl2.h file. - #include // "gl3ext.h" is just a stub file. The real extension header is "gl2ext.h". +// The macros ENABLE_OPENGL_STANDARD and ENABLE_OPENGL_ES are used in client build configs. +// If a client wants to use OpenGL, they must declare one of these two macros somewhere in +// their build config or declare it in some precompiled header. - // Ignore dynamic linking - #define OGLEXT(procPtr, func) - #define INITOGLEXT(procPtr, func) - #define EXTERNOGLEXT(procPtr, func) -#elif defined(__EMSCRIPTEN__) - #define OPENGL_VARIANT_ES - #include - #include - - // Ignore dynamic linking - #define OGLEXT(procPtr, func) - #define INITOGLEXT(procPtr, func) - #define EXTERNOGLEXT(procPtr, func) -#elif defined(_WIN32) - #define OPENGL_VARIANT_STANDARD +// OPENGL PLATFORM-SPECIFIC INCLUDES +#if defined(_WIN32) + #ifndef ENABLE_OPENGL_STANDARD + #define ENABLE_OPENGL_STANDARD // TODO: Declare this in the Visual Studio project file. + #endif #define WIN32_LEAN_AND_MEAN #include #include @@ -63,15 +49,10 @@ #define INITOGLEXT(procPtr, func) func = (procPtr)wglGetProcAddress(#func); #define EXTERNOGLEXT(procPtr, func) extern procPtr func; #elif defined(__APPLE__) - #include - - #if TARGET_OS_IPHONE - #define OPENGL_VARIANT_ES + #if defined(ENABLE_OPENGL_ES) #include #include - #else - #define OPENGL_VARIANT_STANDARD - + #elif defined(ENABLE_OPENGL_STANDARD) #ifdef OGLRENDER_3_2_H #include #include @@ -93,36 +74,46 @@ #define INITOGLEXT(procPtr, func) #define EXTERNOGLEXT(procPtr, func) #else - #define OPENGL_VARIANT_STANDARD - #include - #include - #include + #if defined(ENABLE_OPENGL_ES) + #include + #define __gles2_gl2_h_ // Guard against including the gl2.h file. + #include // "gl3ext.h" is just a stub file. The real extension header is "gl2ext.h". + + // Ignore dynamic linking + #define OGLEXT(procPtr, func) + #define INITOGLEXT(procPtr, func) + #define EXTERNOGLEXT(procPtr, func) + #elif defined(ENABLE_OPENGL_STANDARD) + #include + #include + #include - #ifdef OGLRENDER_3_2_H - #include "utils/glcorearb.h" - #else - /* This is a workaround needed to compile against nvidia GL headers */ - #ifndef GL_ALPHA_BLEND_EQUATION_ATI - #undef GL_VERSION_1_3 + #ifdef OGLRENDER_3_2_H + #include "utils/glcorearb.h" + #else + // This is a workaround needed to compile against nvidia GL headers + #ifndef GL_ALPHA_BLEND_EQUATION_ATI + #undef GL_VERSION_1_3 + #endif #endif - #endif - #define OGLEXT(procPtr, func) procPtr func = NULL; - #define INITOGLEXT(procPtr, func) func = (procPtr)glXGetProcAddress((const GLubyte *) #func); - #define EXTERNOGLEXT(procPtr, func) extern procPtr func; + #define OGLEXT(procPtr, func) procPtr func = NULL; + #define INITOGLEXT(procPtr, func) func = (procPtr)glXGetProcAddress((const GLubyte *) #func); + #define EXTERNOGLEXT(procPtr, func) extern procPtr func; + #endif #endif // Check minimum OpenGL header version -#if defined(OPENGL_VARIANT_STANDARD) - #if !defined(GL_VERSION_2_1) - #error OpenGL requires v2.1 headers or later. - #endif -#elif defined(OPENGL_VARIANT_ES) +#if defined(ENABLE_OPENGL_ES) #if !defined(GL_ES_VERSION_3_0) #error OpenGL ES requires v3.0 headers or later. #endif +#elif defined(ENABLE_OPENGL_STANDARD) + #if !defined(GL_VERSION_2_1) + #error Standard OpenGL requires v2.1 headers or later. + #endif #else - #error Unknown OpenGL variant. + #error No OpenGL variant selected. You must declare ENABLE_OPENGL_STANDARD or ENABLE_OPENGL_ES in your build configuration. #endif // OPENGL LEGACY CORE FUNCTIONS diff --git a/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj b/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj index f1b964a5a..b674e6082 100755 --- a/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj +++ b/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj @@ -4416,6 +4416,8 @@ ABD2CE4426E05CB000FB15F7 /* DeSmuME (x86_64h).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DeSmuME (x86_64h).app"; sourceTree = BUILT_PRODUCTS_DIR; }; ABD42045172319D1006A9B46 /* FileMigrationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileMigrationDelegate.h; sourceTree = ""; }; ABD42046172319D1006A9B46 /* FileMigrationDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FileMigrationDelegate.mm; sourceTree = ""; }; + ABDD89EF2C30BE97003482B7 /* OGLRender_ES3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OGLRender_ES3.h; sourceTree = ""; }; + ABDD89F02C30BE97003482B7 /* OGLRender_ES3.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = OGLRender_ES3.cpp; sourceTree = ""; }; ABDDF7C41898F024007583C1 /* Icon_DisplayToggle_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_DisplayToggle_420x420.png; path = images/Icon_DisplayToggle_420x420.png; sourceTree = ""; }; ABDDF7C71898F032007583C1 /* Icon_FrameAdvance_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_FrameAdvance_420x420.png; path = images/Icon_FrameAdvance_420x420.png; sourceTree = ""; }; ABDDF7C81898F032007583C1 /* Icon_FrameJump_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_FrameJump_420x420.png; path = images/Icon_FrameJump_420x420.png; sourceTree = ""; }; @@ -5692,6 +5694,7 @@ ABD1FEC01345AC8400AF11D1 /* NDSSystem.cpp */, ABD1FEC11345AC8400AF11D1 /* OGLRender.cpp */, AB68A0DA16B139BC00DE0546 /* OGLRender_3_2.cpp */, + ABDD89F02C30BE97003482B7 /* OGLRender_ES3.cpp */, ABD1FEC21345AC8400AF11D1 /* path.cpp */, ABD1FEC31345AC8400AF11D1 /* rasterize.cpp */, ABD1FEC41345AC8400AF11D1 /* readwrite.cpp */, @@ -5739,6 +5742,7 @@ ABD1FE8C1345AC8400AF11D1 /* NDSSystem.h */, ABD1FE8D1345AC8400AF11D1 /* OGLRender.h */, ABBB421516B4A5F30012E5AB /* OGLRender_3_2.h */, + ABDD89EF2C30BE97003482B7 /* OGLRender_ES3.h */, ABD1FE8F1345AC8400AF11D1 /* PACKED.h */, ABD1FE8E1345AC8400AF11D1 /* PACKED_END.h */, ABD1FE901345AC8400AF11D1 /* path.h */, diff --git a/desmume/src/frontend/cocoa/DeSmuME_Prefix.pch b/desmume/src/frontend/cocoa/DeSmuME_Prefix.pch index e7c124cec..d030561cc 100644 --- a/desmume/src/frontend/cocoa/DeSmuME_Prefix.pch +++ b/desmume/src/frontend/cocoa/DeSmuME_Prefix.pch @@ -1,6 +1,6 @@ /* Copyright (C) 2011 Roger Manuel - Copyright (C) 2012-2021 DeSmuME team + Copyright (C) 2012-2024 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,7 +22,7 @@ #define HOST_DARWIN #define DESMUME_COCOA -#define HAVE_OPENGL +#define ENABLE_OPENGL_STANDARD #define HAVE_LIBZ //#define HAVE_LUA //#define HAVE_AV_CONFIG_H diff --git a/desmume/src/frontend/cocoa/openemu/DeSmuME_Prefix_OpenEmu.pch b/desmume/src/frontend/cocoa/openemu/DeSmuME_Prefix_OpenEmu.pch index 4dd987aa6..0252bfd9b 100644 --- a/desmume/src/frontend/cocoa/openemu/DeSmuME_Prefix_OpenEmu.pch +++ b/desmume/src/frontend/cocoa/openemu/DeSmuME_Prefix_OpenEmu.pch @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2022 DeSmuME team + Copyright (C) 2012-2024 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ #define HOST_DARWIN #define DESMUME_COCOA -#define HAVE_OPENGL +#define ENABLE_OPENGL_STANDARD #define HAVE_LIBZ #define FT2_BUILD_LIBRARY diff --git a/desmume/src/frontend/modules/ImageOut.cpp b/desmume/src/frontend/modules/ImageOut.cpp index f7c5e56df..d0b5e6511 100644 --- a/desmume/src/frontend/modules/ImageOut.cpp +++ b/desmume/src/frontend/modules/ImageOut.cpp @@ -23,7 +23,7 @@ #include "formats/rbmp.h" #include "GPU.h" -static u8* Convert15To24(const u16* src, int width, int height) +u8* Convert15To24(const u16* src, int width, int height) { u8 *tmp_buffer; u8 *tmp_inc; @@ -66,4 +66,4 @@ int NDS_WriteBMP_32bppBuffer(int width, int height, const void* buf, const char { bool ok = rbmp_save_image(filename,buf,width,height,width*4,(rbmp_source_type)(RBMP_SOURCE_TYPE_ARGB8888 | RBMP_SOURCE_TYPE_YFLIPPED)); return ok?1:0; -} \ No newline at end of file +} diff --git a/desmume/src/frontend/posix/Makefile.am b/desmume/src/frontend/posix/Makefile.am index 4329a89e7..7da01eb2f 100644 --- a/desmume/src/frontend/posix/Makefile.am +++ b/desmume/src/frontend/posix/Makefile.am @@ -38,7 +38,6 @@ libdesmume_a_SOURCES = \ ../../wifi.cpp ../../wifi.h \ ../../mic.h \ ../../MMU.cpp ../../MMU.h ../../MMU_timing.h ../../NDSSystem.cpp ../../NDSSystem.h ../../registers.h \ - ../../OGLRender.h ../../OGLRender_3_2.h \ ../../ROMReader.cpp ../../ROMReader.h \ ../../render3D.cpp ../../render3D.h \ ../../rtc.cpp ../../rtc.h \ @@ -211,8 +210,17 @@ endif libdesmume_a_SOURCES += shared/desmume_config.cpp shared/desmume_config.h -if HAVE_GL -libdesmume_a_SOURCES += ../../OGLRender.cpp ../../OGLRender_3_2.cpp +if ENABLE_OPENGL_ES +libdesmume_a_SOURCES += \ + ../../OGLRender.h ../../OGLRender_3_2.h \ + ../../OGLRender.cpp ../../OGLRender_3_2.cpp \ + ../../OGLRender_ES3.h ../../OGLRender_ES3.cpp +else +if ENABLE_OPENGL_STANDARD +libdesmume_a_SOURCES += \ + ../../OGLRender.h ../../OGLRender_3_2.h \ + ../../OGLRender.cpp ../../OGLRender_3_2.cpp +endif endif if HAVE_OPENAL diff --git a/desmume/src/frontend/posix/codeblocks/desmume.cbp b/desmume/src/frontend/posix/codeblocks/desmume.cbp new file mode 100644 index 000000000..120d59b08 --- /dev/null +++ b/desmume/src/frontend/posix/codeblocks/desmume.cbp @@ -0,0 +1,1348 @@ + + + + + + diff --git a/desmume/src/frontend/posix/configure.ac b/desmume/src/frontend/posix/configure.ac index 7b92781e3..89b886618 100644 --- a/desmume/src/frontend/posix/configure.ac +++ b/desmume/src/frontend/posix/configure.ac @@ -70,32 +70,139 @@ else AC_MSG_ERROR([sdl is required to build desmume]) fi -dnl - Check for the OpenGL includes -AC_CHECK_HEADERS([GL/gl.h], - [AC_CHECK_HEADERS([GL/glu.h], [have_gl_h=yes LIBS="$LIBS -lGL -lGLU"], [have_gl_h=no])], - [have_gl_h=no]) -if test "have_gl_h" = "no" ; then - AC_MSG_WARN([Building without GL support because of missing headers.]) +dnl - if --enable-opengl is used, check for it +AC_ARG_ENABLE([opengl], + [AC_HELP_STRING([--enable-opengl], [Build for standard OpenGL])], + [opengl=$enableval], + [opengl=no]) + +if test "x$opengl" = "xyes" ; then + AC_CHECK_HEADERS([GL/gl.h], + [AC_CHECK_HEADERS([GL/glcorearb.h], [have_opengl=yes], [have_opengl=no])], + [have_opengl=no]) + if test "have_opengl" = "no" ; then + AC_MSG_WARN([Cannot build with OpenGL -- headers not found.]) + else + AC_CHECK_LIB(dl, main) + AC_CHECK_LIB(GL, main,[ + AC_DEFINE([ENABLE_OPENGL_STANDARD]) + OPENGL_LIBS="-lGL" + AC_SUBST(OPENGL_LIBS) + ]) + fi fi -AM_CONDITIONAL([HAVE_GL], [test "${have_gl_h}" = "yes"]) +AM_CONDITIONAL([ENABLE_OPENGL_STANDARD], [test "${have_opengl}" = "yes"]) + +dnl - if --enable-opengles is used, check for it +AC_ARG_ENABLE([opengles], + [AC_HELP_STRING([--enable-opengles], [Build for OpenGL ES, overrides --enable-opengl])], + [opengles=$enableval], + [opengles=no]) + +if test "x$opengles" = "xyes" ; then + AC_CHECK_HEADERS([GLES3/gl3.h], + [AC_CHECK_HEADERS([GLES3/gl3ext.h], [have_opengles=yes], [have_opengles=no])], + [have_opengles=no]) + if test "have_opengles" = "no" ; then + AC_MSG_WARN([Cannot build with OpenGL ES -- headers not found.]) + else + AC_CHECK_LIB(dl, main) + AC_CHECK_LIB(GLESv2, main,[ + AC_DEFINE([ENABLE_OPENGL_ES]) + OPENGLES_LIBS="-lGLESv2" + AC_SUBST(OPENGLES_LIBS) + ]) + fi +fi +AM_CONDITIONAL([ENABLE_OPENGL_ES], [test "${have_opengles}" = "yes"]) + +dnl - if --enable-glx is used, check for it +AC_ARG_ENABLE([glx], + [AC_HELP_STRING([--enable-glx], [Use a GLX context, overrides --enable-osmesa and --enable-egl])], + [glx=$enableval], + [glx=no]) + +if test "x$glx" = "xyes" ; then + AC_CHECK_HEADERS([GL/glx.h], [have_glx=yes], [have_glx=no]) + if test "have_glx" = "no" ; then + AC_MSG_WARN([Cannot use GLX -- headers not found.]) + else + AC_CHECK_LIB(dl, main) + AC_CHECK_LIB(GL, main) + AC_CHECK_LIB(GLX, main) + fi +fi + +if test "$have_glx" = "yes" ; then + if test "$have_opengl" = "yes" ; then + AC_DEFINE(ENABLE_GLX) + GLX_LIBS="-lGLX" + AC_SUBST(GLX_LIBS) + else + have_glx=no + if test "$have_opengles" = "yes" ; then + AC_MSG_WARN([GLX contexts are incompatible with OpenGL ES -- cancelling the use of GLX.]) + else + AC_MSG_WARN([GLX contexts are only compatible with standard OpenGL -- cancelling the use of GLX.]) + fi + fi +fi +AM_CONDITIONAL([ENABLE_GLX], [test "${have_glx}" = "yes"]) dnl - if --enable-osmesa is used, check for it AC_ARG_ENABLE([osmesa], - [AC_HELP_STRING([--enable-osmesa], [use off-screen mesa])], + [AC_HELP_STRING([--enable-osmesa], [Use an OSMesa context, overrides --enable-egl])], [osmesa=$enableval], [osmesa=no]) if test "x$osmesa" = "xyes" ; then - AC_CHECK_LIB(dl, main) - AC_CHECK_LIB([GL], main) - AC_CHECK_LIB(OSMesa, main,[ - useosmesa=yes - AC_DEFINE(HAVE_LIBOSMESA) - OSMESA_LIBS="-lOSMesa" + AC_CHECK_HEADERS([GL/osmesa.h], [have_osmesa=yes], [have_osmesa=no]) + if test "have_osmesa" = "no" ; then + AC_MSG_WARN([Cannot use OSMesa -- headers not found.]) + else + AC_MSG_WARN([OSMesa contexts are deprecated.]) + AC_CHECK_LIB(dl, main) + AC_CHECK_LIB(GL, main) + AC_CHECK_LIB(OSMesa, main) + fi +fi + +if test "$have_osmesa" = "yes" ; then + if test "$have_opengl" = "yes" ; then + AC_DEFINE(ENABLE_OSMESA) + OSMESA_LIBS="-lOSMesa" AC_SUBST(OSMESA_LIBS) - ]) + else + have_osmesa=no + if test "$have_opengles" = "yes" ; then + AC_MSG_WARN([OSMesa contexts are incompatible with OpenGL ES -- cancelling the use of OSMesa.]) + else + AC_MSG_WARN([OSMesa contexts are only compatible with standard OpenGL -- cancelling the use of OSMesa.]) + fi + fi +fi +AM_CONDITIONAL([ENABLE_OSMESA], [test "${have_osmesa}" = "yes"]) + +dnl - if --enable-egl is used, check for it +AC_ARG_ENABLE([egl], + [AC_HELP_STRING([--enable-egl], [Use an EGL context])], + [egl=$enableval], + [egl=no]) + +if test "x$egl" = "xyes" ; then + AC_CHECK_HEADERS([EGL/egl.h], [have_egl=yes], [have_egl=no]) + if test "have_egl" = "no" ; then + AC_MSG_WARN([Cannot use EGL -- headers not found.]) + else + AC_CHECK_LIB(dl, main) + AC_CHECK_LIB(EGL, main,[ + AC_DEFINE(ENABLE_EGL) + EGL_LIBS="-lEGL" + AC_SUBST(EGL_LIBS) + ]) + fi fi -AM_CONDITIONAL([HAVE_LIBOSMESA], [test "${useosmesa}" = "yes"]) +AM_CONDITIONAL([ENABLE_EGL], [test "${have_egl}" = "yes"]) dnl - make the usage of libagg for HUD rendering configurable AC_ARG_ENABLE([hud], diff --git a/desmume/src/frontend/posix/gtk/Makefile.am b/desmume/src/frontend/posix/gtk/Makefile.am index b38012cde..c4952a715 100644 --- a/desmume/src/frontend/posix/gtk/Makefile.am +++ b/desmume/src/frontend/posix/gtk/Makefile.am @@ -9,26 +9,47 @@ pixmapdir = $(datadir)/pixmaps pixmap_DATA = DeSmuME.svg EXTRA_DIST = DeSmuME.svg desmume.desktop bin_PROGRAMS = desmume + desmume_SOURCES = \ - avout.h \ - avout_pipe_base.cpp avout_pipe_base.h \ - avout_x264.cpp avout_x264.h \ - avout_flac.cpp avout_flac.h \ + ../shared/avout.h \ + ../shared/avout_flac.h ../shared/avout_flac.cpp \ + ../shared/avout_pipe_base.h ../shared/avout_pipe_base.cpp \ + ../shared/avout_x264.h ../shared/avout_x264.cpp \ + ../shared/ctrlssdl.h ../shared/ctrlssdl.cpp \ + ../shared/sndsdl.cpp \ config.cpp config.h config_opts.h \ desmume.h desmume.cpp \ dTool.h dToolsList.cpp \ tools/ioregsView.cpp tools/ioregsView.h \ - ../shared/sndsdl.cpp \ - ../shared/ctrlssdl.h ../shared/ctrlssdl.cpp \ - osmesa_3Demu.cpp osmesa_3Demu.h \ - sdl_3Demu.cpp sdl_3Demu.h \ cheatsGTK.h cheatsGTK.cpp \ main.cpp main.h + desmume_LDADD = ../libdesmume.a \ $(X_LIBS) -lX11 $(SDL_LIBS) $(GTK_LIBS) $(GTHREAD_LIBS) $(ALSA_LIBS) $(LIBAGG_LIBS) $(LIBSOUNDTOUCH_LIBS) -if HAVE_LIBOSMESA + +if ENABLE_OPENGL_ES +desmume_LDADD += $(OPENGLES_LIBS) +else +if ENABLE_OPENGL_STANDARD +desmume_LDADD += $(OPENGL_LIBS) +endif +endif + +if ENABLE_GLX +desmume_LDADD += $(GLX_LIBS) +desmume_SOURCES += ../shared/glx_3Demu.h ../shared/glx_3Demu.cpp +else +if ENABLE_OSMESA desmume_LDADD += $(OSMESA_LIBS) +desmume_SOURCES += ../shared/osmesa_3Demu.h ../shared/osmesa_3Demu.cpp else +if ENABLE_EGL +desmume_LDADD += $(EGL_LIBS) +desmume_SOURCES += ../shared/egl_3Demu.h ../shared/egl_3Demu.cpp +else +desmume_SOURCES += ../shared/sdl_3Demu.h ../shared/sdl_3Demu.cpp +endif +endif endif UPDATE_DESKTOP = \ @@ -43,4 +64,4 @@ install-data-hook: $(UPDATE_DESKTOP) uninstall-hook: - $(UPDATE_DESKTOP) + $(UPDATE_DESKTOP) diff --git a/desmume/src/frontend/posix/gtk/graphics.ui b/desmume/src/frontend/posix/gtk/graphics.ui index f8dc2976b..8134782c7 100644 --- a/desmume/src/frontend/posix/gtk/graphics.ui +++ b/desmume/src/frontend/posix/gtk/graphics.ui @@ -1,4 +1,5 @@ + @@ -49,40 +50,49 @@ + + False + False 3D Core: - 0 - 0 + 0 + 0 + False Null SoftRasterizer - OpenGL + OpenGL (Auto) + OpenGL (Legacy) + OpenGL 3.2 + OpenGL ES 3.0 - 1 - 0 + 1 + 0 + False 3D Texture Upscaling: - 0 - 1 + 0 + 1 + False ×1 ×2 @@ -90,70 +100,79 @@ - 1 - 1 + 1 + 1 + False GPU scale factor: - 0 - 2 + 0 + 2 - true - 0 + False + True - 1 - 2 + 1 + 2 3D Texture Deposterization + False + False True - 0 - 3 + 0 + 3 3D Texture Smoothing + False + False True - 0 - 4 + 0 + 4 High Resolution Color Interpolation (SoftRasterizer) + False + False True - 1 - 4 + 1 + 4 + False Multisample Antialiasing (OpenGL): - 0 - 5 + 0 + 5 + False None 2 @@ -164,11 +183,37 @@ - 1 - 5 + 1 + 5 + + + + + + + + + + + + + + + + + + + + + + + False + True + 1 + diff --git a/desmume/src/frontend/posix/gtk/main.cpp b/desmume/src/frontend/posix/gtk/main.cpp index 06f55c656..fe3b51105 100644 --- a/desmume/src/frontend/posix/gtk/main.cpp +++ b/desmume/src/frontend/posix/gtk/main.cpp @@ -1,17 +1,17 @@ /* Copyright (C) 2007 Pascal Giard (evilynux) Copyright (C) 2006-2024 DeSmuME team - + This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with the this software. If not, see . */ @@ -56,8 +56,8 @@ #include "cheatsGTK.h" #include "frontend/modules/osd/agg/agg_osd.h" -#include "avout_x264.h" -#include "avout_flac.h" +#include "../shared/avout_x264.h" +#include "../shared/avout_flac.h" #include "commandline.h" @@ -72,17 +72,22 @@ #include "gdbstub.h" #endif -#define HAVE_OPENGL - -#ifdef HAVE_OPENGL - #include - #include "OGLRender_3_2.h" -#endif - -#if defined(HAVE_LIBOSMESA) - #include "osmesa_3Demu.h" -#else - #include "sdl_3Demu.h" +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) + #if defined(ENABLE_OPENGL_ES) + #include "OGLRender_ES3.h" + #else + #include "OGLRender_3_2.h" + #endif + + #if defined(ENABLE_GLX) + #include "../shared/glx_3Demu.h" + #elif defined(ENABLE_OSMESA) + #include "../shared/osmesa_3Demu.h" + #elif defined(ENABLE_EGL) + #include "../shared/egl_3Demu.h" + #else + #include "../shared/sdl_3Demu.h" + #endif #endif #include "config.h" @@ -344,11 +349,16 @@ NULL }; GPU3DInterface *core3DList[] = { - &gpu3DNull, - &gpu3DRasterize, -#ifdef HAVE_OPENGL - &gpu3Dgl, + &gpu3DNull, + &gpu3DRasterize, +#if defined(ENABLE_OPENGL_ES) + &gpu3Dgl_ES_3_0, +#elif defined(ENABLE_OPENGL_STANDARD) + &gpu3Dgl, + &gpu3DglOld, + &gpu3Dgl_3_2, #endif + NULL }; int multisampleSizes[] = {0, 2, 4, 8, 16, 32}; @@ -409,7 +419,7 @@ init_configured_features( class configured_features *config ) config->timeout = 0; /* use the default language */ - config->firmware_language = -1; + config->firmware_language = -1; /* If specified by --lang option the lang will change to choosed one */ config->firmware_language = config->language; @@ -423,7 +433,7 @@ fill_configured_features( class configured_features *config, { "3d-render", 0, 0, G_OPTION_ARG_INT, &config->engine_3d, "Select 3D rendering engine. Available engines:\n" "\t\t\t\t 0 = 3d disabled\n" "\t\t\t\t 1 = internal rasterizer (default)\n" -#ifdef HAVE_OPENGL +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) "\t\t\t\t 2 = opengl\n" #endif ,"ENGINE"}, @@ -467,12 +477,12 @@ fill_configured_features( class configured_features *config, // Check if the commandLine argument was actually passed if (config->engine_3d != -1) { if (config->engine_3d != 0 && config->engine_3d != 1 -#ifdef HAVE_OPENGL +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) && config->engine_3d != 2 #endif ) { g_printerr("Currently available ENGINES: 0, 1" -#ifdef HAVE_OPENGL +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) ", 2" #endif "\n"); @@ -1531,7 +1541,7 @@ static gboolean ExposeDrawingArea (GtkWidget *widget, GdkEventExpose *event, gpo if(nds_screen.orientation == ORIENT_HYBRID_EQUAL) draw_params.hybridBigScreenScale = (double)(dstH + draw_params.gap) / (double)(dstH / 2); } - + // Calculate scale to fit display area to window gfloat hratio = (gfloat)daW / (gfloat)draw_params.imgW; gfloat vratio = (gfloat)daH / (gfloat)draw_params.imgH; @@ -1821,7 +1831,7 @@ static gboolean Stylus_Release(GtkWidget *w, GdkEventButton *e, gpointer data) static void loadgame(int num){ if (desmume_running()) - { + { Pause(NULL, NULL, NULL); loadstate_slot(num); Launch(NULL, NULL, NULL); @@ -1833,7 +1843,7 @@ static void loadgame(int num){ static void savegame(int num){ if (desmume_running()) - { + { Pause(NULL, NULL, NULL); savestate_slot(num); Launch(NULL, NULL, NULL); @@ -2102,7 +2112,7 @@ static void Modify_JoyKey(GtkWidget* widget, gpointer data) gtk_widget_show_all(gtk_dialog_get_content_area(GTK_DIALOG(mkDialog))); g_signal_connect(G_OBJECT(mkDialog), "focus_in_event", G_CALLBACK(AcceptNewJoyKey), &ctx); - + switch(gtk_dialog_run(GTK_DIALOG(mkDialog))) { case GTK_RESPONSE_OK: Keypad_Temp[Key] = ctx.mk_key_chosen; @@ -2229,8 +2239,18 @@ static void GraphicsSettingsDialog(GSimpleAction *action, GVariant *parameter, g wHCInterpolate = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "hc_interpolate")); g_object_unref(builder); -#ifndef HAVE_OPENGL +#if defined(ENABLE_OPENGL_ES) + gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(coreCombo), 4); + gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(coreCombo), 3); + gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(coreCombo), 2); +#elif defined(ENABLE_OPENGL_STANDARD) + gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(coreCombo), 5); +#else + gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(coreCombo), 5); + gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(coreCombo), 4); + gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(coreCombo), 3); gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(coreCombo), 2); + gtk_grid_remove_row(wGrid, 5); gtk_grid_remove_row(wGrid, 4); #endif gtk_combo_box_set_active(coreCombo, cur3DCore); @@ -2247,7 +2267,7 @@ static void GraphicsSettingsDialog(GSimpleAction *action, GVariant *parameter, g // 3D Texture Smoothing gtk_toggle_button_set_active(wSmoothing, CommonSettings.GFX3D_Renderer_TextureSmoothing); -#ifdef HAVE_OPENGL +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) // OpenGL Multisample int currentMultisample = CommonSettings.GFX3D_Renderer_MultisampleSize; int currentActive = 0; @@ -2270,21 +2290,65 @@ static void GraphicsSettingsDialog(GSimpleAction *action, GVariant *parameter, g // Change only if needed if (sel3DCore != cur3DCore) { - if (sel3DCore == 2) + switch (sel3DCore) { -#if !defined(HAVE_OPENGL) - sel3DCore = RENDERID_SOFTRASTERIZER; -#elif defined(HAVE_LIBOSMESA) - if (!is_osmesa_initialized()) - { - init_osmesa_3Demu(); - } -#else - if (!is_sdl_initialized()) +#if defined(ENABLE_OPENGL_ES) && !defined(ENABLE_OSMESA) && !defined(ENABLE_GLX) + case 2: + #if defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_ES_3_0; + #else + oglrender_init = &sdl_initOpenGL_ES_3_0; + #endif + break; +#elif defined(ENABLE_OPENGL_STANDARD) + case 2: + #if defined(ENABLE_GLX) + oglrender_init = &glx_initOpenGL_StandardAuto; + #elif defined(ENABLE_OSMESA) + oglrender_init = &osmesa_initOpenGL_StandardAuto; + #elif defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_StandardAuto; + #else + oglrender_init = &sdl_initOpenGL_StandardAuto; + #endif + break; + + case 3: + #if defined(ENABLE_GLX) + oglrender_init = &glx_initOpenGL_LegacyAuto; + #elif defined(ENABLE_OSMESA) + oglrender_init = &osmesa_initOpenGL_LegacyAuto; + #elif defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_LegacyAuto; + #else + oglrender_init = &sdl_initOpenGL_LegacyAuto; + #endif + break; + + case 4: + #if defined(ENABLE_GLX) + oglrender_init = &glx_initOpenGL_3_2_CoreProfile; + #elif defined(ENABLE_OSMESA) + oglrender_init = &osmesa_initOpenGL_3_2_CoreProfile; + #elif defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_3_2_CoreProfile; + #else + oglrender_init = &sdl_initOpenGL_3_2_CoreProfile; + #endif + break; +#endif + default: { - init_sdl_3Demu(); + if (sel3DCore > 0) + { + sel3DCore = RENDERID_SOFTRASTERIZER; + } + else + { + sel3DCore = RENDERID_NULL; + } + break; } -#endif } if (GPU->Change3DRendererByID(sel3DCore)) @@ -2342,7 +2406,7 @@ static void GraphicsSettingsDialog(GSimpleAction *action, GVariant *parameter, g CommonSettings.GFX3D_Renderer_TextureSmoothing = config.textureSmoothing = gtk_toggle_button_get_active(wSmoothing); CommonSettings.GFX3D_Renderer_TextureScalingFactor = config.textureUpscale = scale; CommonSettings.GFX3D_HighResolutionInterpolateColor = config.highColorInterpolation = gtk_toggle_button_get_active(wHCInterpolate); -#ifdef HAVE_OPENGL +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) int selectedMultisample = gtk_combo_box_get_active(wMultisample); config.multisamplingSize = multisampleSizes[selectedMultisample]; config.multisampling = selectedMultisample != 0; @@ -2703,7 +2767,7 @@ class GtkDriver : public BaseDriver return avout_x264.isRecording() || avout_flac.isRecording(); } - virtual void AVI_SoundUpdate(void* soundData, int soundLen) { + virtual void AVI_SoundUpdate(void* soundData, int soundLen) { avout_flac.updateAudio(soundData, soundLen); } }; @@ -2774,7 +2838,7 @@ gboolean EmuLoop(gpointer data) #ifdef HAVE_LIBAGG Hud.fps3d = GPU->GetFPSRender3D(); - if(nds.idleFrameCounter==0 || oneSecond) + if (nds.idleFrameCounter==0 || oneSecond) { u32 loadAvgARM9; u32 loadAvgARM7; @@ -3266,7 +3330,7 @@ common_gtk_main(GApplication *app, gpointer user_data) slot2_device_type = NDS_SLOT2_NONE; break; } - + slot2_Init(); slot2_Change((NDS_SLOT2_TYPE)slot2_device_type); @@ -3304,7 +3368,7 @@ common_gtk_main(GApplication *app, gpointer user_data) arm9_gdb_stub = createStub_gdb( my_config->arm9_gdb_port, &NDS_ARM9, &arm9_direct_memory_iface); - + if ( arm9_gdb_stub == NULL) { g_printerr("Failed to create ARM9 gdbstub on port %d\n", my_config->arm9_gdb_port); @@ -3318,7 +3382,7 @@ common_gtk_main(GApplication *app, gpointer user_data) arm7_gdb_stub = createStub_gdb( my_config->arm7_gdb_port, &NDS_ARM7, &arm7_base_memory_iface); - + if ( arm7_gdb_stub == NULL) { g_printerr("Failed to create ARM7 gdbstub on port %d\n", my_config->arm7_gdb_port); @@ -3336,8 +3400,8 @@ common_gtk_main(GApplication *app, gpointer user_data) g_application_quit(app); dTools_running = (BOOL*)malloc(sizeof(BOOL) * dTools_list_size); - if (dTools_running != NULL) - memset(dTools_running, FALSE, sizeof(BOOL) * dTools_list_size); + if (dTools_running != NULL) + memset(dTools_running, FALSE, sizeof(BOOL) * dTools_list_size); keyfile = desmume_config_read_file(gtk_kb_cfg); @@ -3814,22 +3878,60 @@ common_gtk_main(GApplication *app, gpointer user_data) g_simple_action_set_state(G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "enablefpslimiter")), g_variant_new_boolean(FALSE)); } -#if defined(HAVE_OPENGL) && defined(OGLRENDER_3_2_H) +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) + #if defined(OGLRENDER_3_2_H) OGLLoadEntryPoints_3_2_Func = OGLLoadEntryPoints_3_2; OGLCreateRenderer_3_2_Func = OGLCreateRenderer_3_2; -#endif + #endif + #if defined(OGLRENDER_ES3_H) + OGLLoadEntryPoints_ES_3_0_Func = &OGLLoadEntryPoints_ES_3_0; + OGLCreateRenderer_ES_3_0_Func = &OGLCreateRenderer_ES_3_0; + #endif + + #if defined(ENABLE_GLX) + oglrender_init = &glx_initOpenGL_StandardAuto; + oglrender_deinit = &glx_deinitOpenGL; + oglrender_beginOpenGL = &glx_beginOpenGL; + oglrender_endOpenGL = &glx_endOpenGL; + oglrender_framebufferDidResizeCallback = &glx_framebufferDidResizeCallback; + #elif defined(ENABLE_OSMESA) + oglrender_init = &osmesa_initOpenGL_StandardAuto; + oglrender_deinit = &osmesa_deinitOpenGL; + oglrender_beginOpenGL = &osmesa_beginOpenGL; + oglrender_endOpenGL = &osmesa_endOpenGL; + oglrender_framebufferDidResizeCallback = &osmesa_framebufferDidResizeCallback; + #elif defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_StandardAuto; + oglrender_deinit = &egl_deinitOpenGL; + oglrender_beginOpenGL = &egl_beginOpenGL; + oglrender_endOpenGL = &egl_endOpenGL; + oglrender_framebufferDidResizeCallback = &egl_framebufferDidResizeCallback; + #else + oglrender_init = &sdl_initOpenGL_StandardAuto; + oglrender_deinit = &sdl_deinitOpenGL; + oglrender_beginOpenGL = &sdl_beginOpenGL; + oglrender_endOpenGL = &sdl_endOpenGL; + oglrender_framebufferDidResizeCallback = &sdl_framebufferDidResizeCallback; + #endif +#endif // ENABLE_OPENGL_STANDARD || ENABLE_OPENGL_ES //Set the 3D emulation to use int core = my_config->engine_3d; // setup the gdk 3D emulation; // Check if commandLine argument was passed or not - if (core == -1) { + if (core == -1) + { // If it was not passed, then get the Renderer config from the file core = config.core3D; // Check if it is valid - if (!(core >= 0 && core <= 2)) { +#if defined(ENABLE_OPENGL_ES) + if (!(core >= 0 && core <= 2)) +#elif defined(ENABLE_OPENGL_STANDARD) + if (!(core >= 0 && core <= 4)) +#endif + { // If it is invalid, reset it to SoftRasterizer core = 1; } @@ -3837,21 +3939,65 @@ common_gtk_main(GApplication *app, gpointer user_data) my_config->engine_3d = core; } - if (core == 2) + switch (core) { -#if !defined(HAVE_OPENGL) - core = RENDERID_SOFTRASTERIZER; -#elif defined(HAVE_LIBOSMESA) - if (!is_osmesa_initialized()) - { - init_osmesa_3Demu(); - } -#else - if (!is_sdl_initialized()) +#if defined(ENABLE_OPENGL_ES) && !defined(ENABLE_OSMESA) && !defined(ENABLE_GLX) + case 2: + #if defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_ES_3_0; + #else + oglrender_init = &sdl_initOpenGL_ES_3_0; + #endif + break; +#elif defined(ENABLE_OPENGL_STANDARD) + case 2: + #if defined(ENABLE_GLX) + oglrender_init = &glx_initOpenGL_StandardAuto; + #elif defined(ENABLE_OSMESA) + oglrender_init = &osmesa_initOpenGL_StandardAuto; + #elif defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_StandardAuto; + #else + oglrender_init = &sdl_initOpenGL_StandardAuto; + #endif + break; + + case 3: + #if defined(ENABLE_GLX) + oglrender_init = &glx_initOpenGL_LegacyAuto; + #elif defined(ENABLE_OSMESA) + oglrender_init = &osmesa_initOpenGL_LegacyAuto; + #elif defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_LegacyAuto; + #else + oglrender_init = &sdl_initOpenGL_LegacyAuto; + #endif + break; + + case 4: + #if defined(ENABLE_GLX) + oglrender_init = &glx_initOpenGL_3_2_CoreProfile; + #elif defined(ENABLE_OSMESA) + oglrender_init = &osmesa_initOpenGL_3_2_CoreProfile; + #elif defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_3_2_CoreProfile; + #else + oglrender_init = &sdl_initOpenGL_3_2_CoreProfile; + #endif + break; +#endif + default: { - init_sdl_3Demu(); + if (core > 0) + { + core = RENDERID_SOFTRASTERIZER; + } + else + { + core = RENDERID_NULL; + } + break; } -#endif } if (!GPU->Change3DRendererByID(core)) { @@ -3873,7 +4019,7 @@ common_gtk_main(GApplication *app, gpointer user_data) backup_setManualBackupType(my_config->savetype); - // Command line arg + // Command line arg if( my_config->nds_file != "") { if(Open( my_config->nds_file.c_str()) >= 0) { my_config->process_movieCommands(); @@ -3923,11 +4069,17 @@ static void Teardown() { desmume_free(); -#if defined(HAVE_LIBOSMESA) - deinit_osmesa_3Demu(); -#else - deinit_sdl_3Demu(); -#endif +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) + #if defined(ENABLE_GLX) + glx_deinitOpenGL(); + #elif defined(ENABLE_OSMESA) + osmesa_deinitOpenGL(); + #elif defined(ENABLE_EGL) + egl_deinitOpenGL(); + #else + sdl_deinitOpenGL(); + #endif +#endif // ENABLE_OPENGL_STANDARD || ENABLE_OPENGL_ES /* Unload joystick */ uninit_joy(); diff --git a/desmume/src/frontend/posix/gtk/meson.build b/desmume/src/frontend/posix/gtk/meson.build index 99d6fd1dc..2bdc70356 100644 --- a/desmume/src/frontend/posix/gtk/meson.build +++ b/desmume/src/frontend/posix/gtk/meson.build @@ -10,22 +10,44 @@ gresource = gnome.compile_resources( ) desmume_src = [ - 'avout_pipe_base.cpp', - 'avout_x264.cpp', - 'avout_flac.cpp', + '../shared/avout_flac.cpp', + '../shared/avout_pipe_base.cpp', + '../shared/avout_x264.cpp', + '../shared/ctrlssdl.cpp', + '../shared/sndsdl.cpp', 'config.cpp', 'desmume.cpp', 'dToolsList.cpp', 'tools/ioregsView.cpp', - '../shared/sndsdl.cpp', - '../shared/ctrlssdl.cpp', - 'osmesa_3Demu.cpp', - 'sdl_3Demu.cpp', 'cheatsGTK.cpp', 'main.cpp', gresource, ] +if get_option('glx') and dep_glx.found() + add_global_arguments('-DENABLE_GLX', language: ['c', 'cpp']) + dependencies += dep_glx + desmume_src += [ + '../shared/glx_3Demu.cpp', + ] +elif get_option('osmesa') and dep_osmesa.found() + add_global_arguments('-DENABLE_OSMESA', language: ['c', 'cpp']) + dependencies += dep_osmesa + desmume_src += [ + '../shared/osmesa_3Demu.cpp', + ] +elif get_option('egl') and dep_egl.found() + add_global_arguments('-DENABLE_EGL', language: ['c', 'cpp']) + dependencies += dep_egl + desmume_src += [ + '../shared/egl_3Demu.cpp', + ] +else + desmume_src += [ + '../shared/sdl_3Demu.cpp', + ] +endif + # TODO: why do we have to redeclare it here with one more fs level? includes = include_directories( '../../../../src', diff --git a/desmume/src/frontend/posix/gtk/osmesa_3Demu.cpp b/desmume/src/frontend/posix/gtk/osmesa_3Demu.cpp deleted file mode 100644 index 78bf89a2e..000000000 --- a/desmume/src/frontend/posix/gtk/osmesa_3Demu.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - Copyright (C) 2009 Guillaume Duhamel - Copyright (C) 2009-2024 DeSmuME team - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the this software. If not, see . - */ - -#ifdef HAVE_LIBOSMESA - -#include -#include -#include "../OGLRender_3_2.h" - -#include "osmesa_3Demu.h" - -static void *buffer = NULL; -static OSMesaContext ctx = NULL; - -static bool osmesa_beginOpenGL(void) { return 1; } -static void osmesa_endOpenGL(void) { } -static bool osmesa_init(void) { return is_osmesa_initialized(); } - -void deinit_osmesa_3Demu (void) -{ - free(buffer); - buffer = NULL; - - OSMesaDestroyContext(ctx); - ctx = NULL; -} - -bool init_osmesa_3Demu(void) -{ -#if (((OSMESA_MAJOR_VERSION * 100) + OSMESA_MINOR_VERSION) >= 1102) && defined(OSMESA_CONTEXT_MAJOR_VERSION) - static const int attributes_3_2_core_profile[] = { - OSMESA_FORMAT, OSMESA_RGBA, - OSMESA_DEPTH_BITS, 24, - OSMESA_STENCIL_BITS, 8, - OSMESA_ACCUM_BITS, 0, - OSMESA_PROFILE, OSMESA_CORE_PROFILE, - OSMESA_CONTEXT_MAJOR_VERSION, 3, - OSMESA_CONTEXT_MINOR_VERSION, 2, - 0 }; - - ctx = OSMesaCreateContextAttribs(attributes_3_2_core_profile, NULL); - if (ctx == NULL) - { - printf("OSMesa: Could not create a 3.2 Core Profile context. Will attempt to create a 2.1 compatibility context...\n"); - - static const int attributes_2_1[] = { - OSMESA_FORMAT, OSMESA_RGBA, - OSMESA_DEPTH_BITS, 24, - OSMESA_STENCIL_BITS, 8, - OSMESA_ACCUM_BITS, 0, - OSMESA_PROFILE, OSMESA_COMPAT_PROFILE, - OSMESA_CONTEXT_MAJOR_VERSION, 2, - OSMESA_CONTEXT_MINOR_VERSION, 1, - 0 }; - - ctx = OSMesaCreateContextAttribs(attributes_2_1, NULL); - } -#endif - - if (ctx == NULL) - { - ctx = OSMesaCreateContextExt(OSMESA_RGBA, 24, 8, 0, NULL); - if (ctx == NULL) - { - printf("OSMesa: OSMesaCreateContextExt() failed!\n"); - return false; - } - } - - buffer = malloc(GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(uint32_t)); - if (!buffer) - { - printf("OSMesa: Could not allocate enough memory for the context!\n"); - return false; - } - - if (!OSMesaMakeCurrent(ctx, buffer, GL_UNSIGNED_BYTE, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT)) - { - printf("OSMesa: OSMesaMakeCurrent() failed!\n"); - free(buffer); - return false; - } - - oglrender_init = osmesa_init; - oglrender_beginOpenGL = osmesa_beginOpenGL; - oglrender_endOpenGL = osmesa_endOpenGL; - - return true; -} - -bool is_osmesa_initialized(void) -{ - return (ctx != NULL); -} - -#endif diff --git a/desmume/src/frontend/posix/gtk/osmesa_3Demu.h b/desmume/src/frontend/posix/gtk/osmesa_3Demu.h deleted file mode 100644 index af6a9f4db..000000000 --- a/desmume/src/frontend/posix/gtk/osmesa_3Demu.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - Copyright (C) 2009 Guillaume Duhamel - Copyright (C) 2009-2017 DeSmuME team - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the this software. If not, see . - */ - -#ifndef OSMESA_3DEMU_H -#define OSMESA_3DEMU_H - -bool init_osmesa_3Demu(void); -void deinit_osmesa_3Demu(void); -bool is_osmesa_initialized(void); - -#endif // OSMESA_3DEMU_H - diff --git a/desmume/src/frontend/posix/gtk/sdl_3Demu.cpp b/desmume/src/frontend/posix/gtk/sdl_3Demu.cpp deleted file mode 100644 index 39c5d0d57..000000000 --- a/desmume/src/frontend/posix/gtk/sdl_3Demu.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - Copyright (C) 2020 Emmanuel Gil Peyrot - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the this software. If not, see . - */ - -#include -#include -#include "../OGLRender.h" - -#include "sdl_3Demu.h" - -static bool sdl_beginOpenGL(void) { return 1; } -static void sdl_endOpenGL(void) { } -static bool sdl_init(void) { return is_sdl_initialized(); } - -static SDL_Window *win = NULL; -static SDL_GLContext ctx = NULL; - -extern int real_framebuffer_width; -extern int real_framebuffer_height; - -bool deinit_sdl_3Demu(void) -{ - bool ret = false; - - if (ctx) { - SDL_GL_DeleteContext(ctx); - ctx = NULL; - ret = true; - } - - if (win) { - SDL_DestroyWindow(win); - win = NULL; - ret = true; - } - - return ret; -} - -bool init_sdl_3Demu(void) -{ - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); - - win = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, real_framebuffer_width, - real_framebuffer_height, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN); - if (!win) { - fprintf(stderr, "SDL: Failed to create a window: %s\n", SDL_GetError()); - return false; - } - - ctx = SDL_GL_CreateContext(win); - if (!ctx) { - fprintf(stderr, "SDL: Failed to create an OpenGL context: %s\n", SDL_GetError()); - return false; - } - - printf("OGL/SDL Renderer has finished the initialization.\n"); - - oglrender_init = sdl_init; - oglrender_beginOpenGL = sdl_beginOpenGL; - oglrender_endOpenGL = sdl_endOpenGL; - - return true; -} - -bool is_sdl_initialized(void) -{ - return (ctx != NULL); -} diff --git a/desmume/src/frontend/posix/gtk/sdl_3Demu.h b/desmume/src/frontend/posix/gtk/sdl_3Demu.h deleted file mode 100644 index 2088263da..000000000 --- a/desmume/src/frontend/posix/gtk/sdl_3Demu.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - Copyright (C) 2020 Emmanuel Gil Peyrot - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the this software. If not, see . - */ - -#ifndef SDL_3DEMU_H -#define SDL_3DEMU_H - -bool init_sdl_3Demu(void); -bool deinit_sdl_3Demu(void); -bool is_sdl_initialized(void); - -#endif // SDL_3DEMU_H - diff --git a/desmume/src/frontend/posix/gtk2/Makefile.am b/desmume/src/frontend/posix/gtk2/Makefile.am index 9ba2a51b4..1f155dc45 100644 --- a/desmume/src/frontend/posix/gtk2/Makefile.am +++ b/desmume/src/frontend/posix/gtk2/Makefile.am @@ -9,26 +9,47 @@ pixmapdir = $(datadir)/pixmaps pixmap_DATA = DeSmuME.xpm EXTRA_DIST = DeSmuME.xpm desmume.desktop bin_PROGRAMS = desmume + desmume_SOURCES = \ - avout.h \ - avout_pipe_base.cpp avout_pipe_base.h \ - avout_x264.cpp avout_x264.h \ - avout_flac.cpp avout_flac.h \ + ../shared/avout.h \ + ../shared/avout_flac.h ../shared/avout_flac.cpp \ + ../shared/avout_pipe_base.h ../shared/avout_pipe_base.cpp \ + ../shared/avout_x264.h ../shared/avout_x264.cpp \ + ../shared/ctrlssdl.h ../shared/ctrlssdl.cpp \ + ../shared/sndsdl.cpp \ config.cpp config.h config_opts.h \ desmume.h desmume.cpp \ dTool.h dToolsList.cpp \ tools/ioregsView.cpp tools/ioregsView.h \ - ../shared/sndsdl.cpp \ - ../shared/ctrlssdl.h ../shared/ctrlssdl.cpp \ - osmesa_3Demu.cpp osmesa_3Demu.h \ - sdl_3Demu.cpp sdl_3Demu.h \ cheatsGTK.h cheatsGTK.cpp \ main.cpp main.h + desmume_LDADD = ../libdesmume.a \ $(X_LIBS) -lX11 $(SDL_LIBS) $(GTK_LIBS) $(GTHREAD_LIBS) $(ALSA_LIBS) $(LIBAGG_LIBS) $(LIBSOUNDTOUCH_LIBS) -if HAVE_LIBOSMESA + +if ENABLE_OPENGL_ES +desmume_LDADD += $(OPENGLES_LIBS) +else +if ENABLE_OPENGL_STANDARD +desmume_LDADD += $(OPENGL_LIBS) +endif +endif + +if ENABLE_GLX +desmume_LDADD += $(GLX_LIBS) +desmume_SOURCES += ../shared/glx_3Demu.h ../shared/glx_3Demu.cpp +else +if ENABLE_OSMESA desmume_LDADD += $(OSMESA_LIBS) +desmume_SOURCES += ../shared/osmesa_3Demu.h ../shared/osmesa_3Demu.cpp else +if ENABLE_EGL +desmume_LDADD += $(EGL_LIBS) +desmume_SOURCES += ../shared/egl_3Demu.h ../shared/egl_3Demu.cpp +else +desmume_SOURCES += ../shared/sdl_3Demu.h ../shared/sdl_3Demu.cpp +endif +endif endif UPDATE_DESKTOP = \ @@ -43,4 +64,4 @@ install-data-hook: $(UPDATE_DESKTOP) uninstall-hook: - $(UPDATE_DESKTOP) + $(UPDATE_DESKTOP) diff --git a/desmume/src/frontend/posix/gtk2/avout_flac.cpp b/desmume/src/frontend/posix/gtk2/avout_flac.cpp deleted file mode 100644 index a45e77bc0..000000000 --- a/desmume/src/frontend/posix/gtk2/avout_flac.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - Copyright (C) 2014 DeSmuME team - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the this software. If not, see . -*/ - -#include -#include - -#include "avout_flac.h" -#include "SPU.h" - -// Helper macros to convert numerics to strings -#if defined(_MSC_VER) - //re: http://72.14.203.104/search?q=cache:HG-okth5NGkJ:mail.python.org/pipermail/python-checkins/2002-November/030704.html+_msc_ver+compiler+version+string&hl=en&gl=us&ct=clnk&cd=5 - #define _Py_STRINGIZE(X) _Py_STRINGIZE1((X)) - #define _Py_STRINGIZE1(X) _Py_STRINGIZE2 ## X - #define _Py_STRINGIZE2(X) #X - - #define TOSTRING(X) _Py_STRINGIZE(X) // Alias _Py_STRINGIZE so that we have a common macro name -#else - #define STRINGIFY(x) #x - #define TOSTRING(x) STRINGIFY(x) -#endif - -AVOutFlac::AVOutFlac() { - const char* const args[] = { - "flac", - "-f", - "-o", this->filename, - "--endian=little", - "--channels=2", - "--bps=16", - "--sample-rate=" TOSTRING(DESMUME_SAMPLE_RATE), - "--sign=signed", - "--force-raw-format", - "-", - NULL - }; - memcpy(this->args, args, sizeof(args)); -} - -const char* const* AVOutFlac::getArgv(const char* fname) { - if (strlen(fname) >= sizeof(this->filename)) { - return NULL; - } - strncpy(this->filename, fname, sizeof(this->filename)); - return this->args; -} - diff --git a/desmume/src/frontend/posix/gtk2/avout_flac.h b/desmume/src/frontend/posix/gtk2/avout_flac.h deleted file mode 100644 index 818d81665..000000000 --- a/desmume/src/frontend/posix/gtk2/avout_flac.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - Copyright (C) 2014 DeSmuME team - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the this software. If not, see . -*/ - -#ifndef _AVOUT_FLAC_H_ -#define _AVOUT_FLAC_H_ - -#include "avout_pipe_base.h" - -class AVOutFlac : public AVOutPipeBase { -public: - AVOutFlac(); -protected: - Type type() { return TYPE_AUDIO; } - const char* const* getArgv(const char* fname); -private: - char filename[1024]; - const char* args[12]; -}; - -#endif diff --git a/desmume/src/frontend/posix/gtk2/avout_pipe_base.cpp b/desmume/src/frontend/posix/gtk2/avout_pipe_base.cpp deleted file mode 100644 index fa4f5d431..000000000 --- a/desmume/src/frontend/posix/gtk2/avout_pipe_base.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - Copyright (C) 2014 DeSmuME team - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the this software. If not, see . -*/ - -#include -#include - -#include "types.h" -#include "SPU.h" - -#include "avout_pipe_base.h" - -static inline int writeAll(int fd, const void* buf, size_t count) { - ssize_t written = 0, writtenTotal = 0; - do { - written = write(fd, ((u8*)buf) + writtenTotal, count - writtenTotal); - } while (written >= 0 && (writtenTotal += written) < count); - return written; -} - -bool AVOutPipeBase::begin(const char* fname) { - if (this->recording) { - return false; - } - const char* const* args = this->getArgv(fname); - if (args == NULL) { - return false; - } - int pipefd[2]; - if (pipe(pipefd) < 0) { - fprintf(stderr, "Fail to open pipe\n"); - return false; - } - pid_t pid = fork(); - if (pid == 0) { - close(pipefd[1]); - dup2(pipefd[0], STDIN_FILENO); - execvp(args[0], (char* const*)args); - fprintf(stderr, "Fail to start %s: %d %s\n", args[0], errno, strerror(errno)); - _exit(1); - } - close(pipefd[0]); - this->pipe_fd = pipefd[1]; - this->recording = true; - return true; -} - -void AVOutPipeBase::end() { - if (this->recording) { - close(this->pipe_fd); - this->recording = false; - } -} - -bool AVOutPipeBase::isRecording() { - return this->recording; -} - -void AVOutPipeBase::updateAudio(void* soundData, int soundLen) { - if(!this->recording || this->type() != TYPE_AUDIO) { - return; - } - if (writeAll(this->pipe_fd, soundData, soundLen * 2 * 2) == -1) { - fprintf(stderr, "Error on writing audio: %d %s\n", errno, strerror(errno)); - this->end(); - } -} - -void AVOutPipeBase::updateVideo(const u16* buffer) { - if(!this->recording || this->type() != TYPE_VIDEO) { - return; - } - u8 rgb[256 * 384 * 3]; - u8* cur = rgb; - for (int i = 0; i < 256 * 384; i++) { - u16 gpu_pixel = buffer[i]; - *cur = ((gpu_pixel >> 0) & 0x1f) << 3; - cur++; - *cur = ((gpu_pixel >> 5) & 0x1f) << 3; - cur++; - *cur = ((gpu_pixel >> 10) & 0x1f) << 3; - cur++; - } - if (write(this->pipe_fd, rgb, 256 * 384 * 3) == -1) { - fprintf(stderr, "Error on writing video: %d %s\n", errno, strerror(errno)); - this->end(); - } -} - diff --git a/desmume/src/frontend/posix/gtk2/avout_pipe_base.h b/desmume/src/frontend/posix/gtk2/avout_pipe_base.h deleted file mode 100644 index 3f1c0edd8..000000000 --- a/desmume/src/frontend/posix/gtk2/avout_pipe_base.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - Copyright (C) 2014 DeSmuME team - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the this software. If not, see . -*/ - -#ifndef _AVOUT_PIPE_BASE_H_ -#define _AVOUT_PIPE_BASE_H_ - -#include "avout.h" - -class AVOutPipeBase : public AVOut { -public: - bool begin(const char* fname); - void end(); - bool isRecording(); - void updateAudio(void* soundData, int soundLen); - void updateVideo(const u16* buffer); -protected: - enum Type { TYPE_AUDIO, TYPE_VIDEO }; - virtual Type type() = 0; - virtual const char* const* getArgv(const char* fname) = 0; -private: - bool recording; - int pipe_fd; -}; - -#endif diff --git a/desmume/src/frontend/posix/gtk2/avout_x264.cpp b/desmume/src/frontend/posix/gtk2/avout_x264.cpp deleted file mode 100644 index 1996c0f8a..000000000 --- a/desmume/src/frontend/posix/gtk2/avout_x264.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright (C) 2014 DeSmuME team - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the this software. If not, see . -*/ - -#include -#include - -#include "avout_x264.h" - -AVOutX264::AVOutX264() { - const char* const args[] = { - "x264", - "--qp", "0", - "--demuxer", "raw", - "--input-csp", "rgb", - "--input-depth", "8", - "--input-res", "256x384", - "--fps", "60", - "--output-csp", "i444", - "-o", this->filename, - "-", - NULL - }; - memcpy(this->args, args, sizeof(args)); -} - -const char* const* AVOutX264::getArgv(const char* fname) { - if (strlen(fname) >= sizeof(this->filename)) { - return NULL; - } - strncpy(this->filename, fname, sizeof(this->filename)); - return this->args; -} - diff --git a/desmume/src/frontend/posix/gtk2/main.cpp b/desmume/src/frontend/posix/gtk2/main.cpp index cee54cd60..a5450b719 100644 --- a/desmume/src/frontend/posix/gtk2/main.cpp +++ b/desmume/src/frontend/posix/gtk2/main.cpp @@ -1,17 +1,17 @@ /* Copyright (C) 2007 Pascal Giard (evilynux) Copyright (C) 2006-2024 DeSmuME team - + This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with the this software. If not, see . */ @@ -52,8 +52,8 @@ #include "cheatsGTK.h" #include "frontend/modules/osd/agg/agg_osd.h" -#include "avout_x264.h" -#include "avout_flac.h" +#include "../shared/avout_x264.h" +#include "../shared/avout_flac.h" #include "commandline.h" @@ -68,17 +68,22 @@ #include "gdbstub.h" #endif -#define HAVE_OPENGL - -#ifdef HAVE_OPENGL - #include - #include "OGLRender_3_2.h" -#endif - -#if defined(HAVE_LIBOSMESA) - #include "osmesa_3Demu.h" -#else - #include "sdl_3Demu.h" +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) + #if defined(ENABLE_OPENGL_ES) + #include "OGLRender_ES3.h" + #else + #include "OGLRender_3_2.h" + #endif + + #if defined(ENABLE_GLX) + #include "../shared/glx_3Demu.h" + #elif defined(ENABLE_OSMESA) + #include "../shared/osmesa_3Demu.h" + #elif defined(ENABLE_EGL) + #include "../shared/egl_3Demu.h" + #else + #include "../shared/sdl_3Demu.h" + #endif #endif #include "config.h" @@ -396,7 +401,7 @@ static const char *ui_description = " " " " ""; - + static const GtkActionEntry action_entries[] = { { "FileMenu", NULL, "_File" }, { "open", "gtk-open", "_Open", "o", NULL, OpenNdsDialog }, @@ -632,11 +637,16 @@ NULL }; GPU3DInterface *core3DList[] = { - &gpu3DNull, - &gpu3DRasterize, -#ifdef HAVE_OPENGL - &gpu3Dgl, + &gpu3DNull, + &gpu3DRasterize, +#if defined(ENABLE_OPENGL_ES) + &gpu3Dgl_ES_3_0, +#elif defined(ENABLE_OPENGL_STANDARD) + &gpu3Dgl, + &gpu3DglOld, + &gpu3Dgl_3_2, #endif + NULL }; int multisampleSizes[] = {0, 2, 4, 8, 16, 32}; @@ -698,7 +708,7 @@ init_configured_features( class configured_features *config ) config->timeout = 0; /* use the default language */ - config->firmware_language = -1; + config->firmware_language = -1; /* If specified by --lang option the lang will change to choosed one */ config->firmware_language = config->language; @@ -712,7 +722,7 @@ fill_configured_features( class configured_features *config, { "3d-render", 0, 0, G_OPTION_ARG_INT, &config->engine_3d, "Select 3D rendering engine. Available engines:\n" "\t\t\t\t 0 = 3d disabled\n" "\t\t\t\t 1 = internal rasterizer (default)\n" -#ifdef HAVE_OPENGL +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) "\t\t\t\t 2 = opengl\n" #endif ,"ENGINE"}, @@ -756,12 +766,12 @@ fill_configured_features( class configured_features *config, // Check if the commandLine argument was actually passed if (config->engine_3d != -1) { if (config->engine_3d != 0 && config->engine_3d != 1 -#ifdef HAVE_OPENGL +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) && config->engine_3d != 2 #endif ) { g_printerr("Currently available ENGINES: 0, 1" -#ifdef HAVE_OPENGL +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) ", 2" #endif "\n"); @@ -1954,7 +1964,7 @@ static gboolean Stylus_Release(GtkWidget *w, GdkEventButton *e, gpointer data) static void loadgame(int num){ if (desmume_running()) - { + { Pause(); loadstate_slot(num); Launch(); @@ -1966,7 +1976,7 @@ static void loadgame(int num){ static void savegame(int num){ if (desmume_running()) - { + { Pause(); savestate_slot(num); Launch(); @@ -2247,7 +2257,7 @@ static void Modify_JoyKey(GtkWidget* widget, gpointer data) gtk_widget_show_all(gtk_dialog_get_content_area(GTK_DIALOG(mkDialog))); g_signal_connect(G_OBJECT(mkDialog), "focus_in_event", G_CALLBACK(AcceptNewJoyKey), &ctx); - + switch(gtk_dialog_run(GTK_DIALOG(mkDialog))) { case GTK_RESPONSE_OK: Keypad_Temp[Key] = ctx.mk_key_chosen; @@ -2403,8 +2413,12 @@ static void GraphicsSettingsDialog() { coreCombo = gtk_combo_box_text_new(); gtk_combo_box_text_insert_text(GTK_COMBO_BOX_TEXT(coreCombo), 0, "Null"); gtk_combo_box_text_insert_text(GTK_COMBO_BOX_TEXT(coreCombo), 1, "SoftRasterizer"); -#ifdef HAVE_OPENGL - gtk_combo_box_text_insert_text(GTK_COMBO_BOX_TEXT(coreCombo), 2, "OpenGL"); +#if defined(ENABLE_OPENGL_ES) + gtk_combo_box_text_insert_text(GTK_COMBO_BOX_TEXT(coreCombo), 2, "OpenGL ES 3.0"); +#elif defined(ENABLE_OPENGL_STANDARD) + gtk_combo_box_text_insert_text(GTK_COMBO_BOX_TEXT(coreCombo), 2, "OpenGL (Auto)"); + gtk_combo_box_text_insert_text(GTK_COMBO_BOX_TEXT(coreCombo), 3, "OpenGL (Legacy)"); + gtk_combo_box_text_insert_text(GTK_COMBO_BOX_TEXT(coreCombo), 4, "OpenGL 3.2"); #endif gtk_combo_box_set_active(GTK_COMBO_BOX(coreCombo), cur3DCore); gtk_table_attach(GTK_TABLE(wTable), coreCombo, 1, 2, 0, 1, @@ -2447,7 +2461,7 @@ static void GraphicsSettingsDialog() { static_cast(GTK_EXPAND | GTK_FILL), 0, 0); -#ifdef HAVE_OPENGL +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) // OpenGL Multisample gsKey = gtk_label_new("Multisample Antialiasing (OpenGL):"); gtk_misc_set_alignment(GTK_MISC(gsKey), 0.0, 0.5); @@ -2492,21 +2506,65 @@ static void GraphicsSettingsDialog() { // Change only if needed if (sel3DCore != cur3DCore) { - if (sel3DCore == 2) + switch (sel3DCore) { -#if !defined(HAVE_OPENGL) - sel3DCore = RENDERID_SOFTRASTERIZER; -#elif defined(HAVE_LIBOSMESA) - if (!is_osmesa_initialized()) - { - init_osmesa_3Demu(); - } -#else - if (!is_sdl_initialized()) +#if defined(ENABLE_OPENGL_ES) && !defined(ENABLE_OSMESA) && !defined(ENABLE_GLX) + case 2: + #if defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_ES_3_0; + #else + oglrender_init = &sdl_initOpenGL_ES_3_0; + #endif + break; +#elif defined(ENABLE_OPENGL_STANDARD) + case 2: + #if defined(ENABLE_GLX) + oglrender_init = &glx_initOpenGL_StandardAuto; + #elif defined(ENABLE_OSMESA) + oglrender_init = &osmesa_initOpenGL_StandardAuto; + #elif defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_StandardAuto; + #else + oglrender_init = &sdl_initOpenGL_StandardAuto; + #endif + break; + + case 3: + #if defined(ENABLE_GLX) + oglrender_init = &glx_initOpenGL_LegacyAuto; + #elif defined(ENABLE_OSMESA) + oglrender_init = &osmesa_initOpenGL_LegacyAuto; + #elif defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_LegacyAuto; + #else + oglrender_init = &sdl_initOpenGL_LegacyAuto; + #endif + break; + + case 4: + #if defined(ENABLE_GLX) + oglrender_init = &glx_initOpenGL_3_2_CoreProfile; + #elif defined(ENABLE_OSMESA) + oglrender_init = &osmesa_initOpenGL_3_2_CoreProfile; + #elif defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_3_2_CoreProfile; + #else + oglrender_init = &sdl_initOpenGL_3_2_CoreProfile; + #endif + break; +#endif + default: { - init_sdl_3Demu(); + if (sel3DCore > 0) + { + sel3DCore = RENDERID_SOFTRASTERIZER; + } + else + { + sel3DCore = RENDERID_NULL; + } + break; } -#endif } if (GPU->Change3DRendererByID(sel3DCore)) @@ -2537,7 +2595,7 @@ static void GraphicsSettingsDialog() { CommonSettings.GFX3D_Renderer_TextureSmoothing = config.textureSmoothing = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wSmoothing)); CommonSettings.GFX3D_Renderer_TextureScalingFactor = config.textureUpscale = scale; CommonSettings.GFX3D_HighResolutionInterpolateColor = config.highColorInterpolation = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wHCInterpolate)); -#ifdef HAVE_OPENGL +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) int selectedMultisample = gtk_combo_box_get_active(GTK_COMBO_BOX(wMultisample)); config.multisamplingSize = multisampleSizes[selectedMultisample]; config.multisampling = selectedMultisample != 0; @@ -2812,7 +2870,7 @@ class GtkDriver : public BaseDriver return avout_x264.isRecording() || avout_flac.isRecording(); } - virtual void AVI_SoundUpdate(void* soundData, int soundLen) { + virtual void AVI_SoundUpdate(void* soundData, int soundLen) { avout_flac.updateAudio(soundData, soundLen); } }; @@ -2876,7 +2934,7 @@ gboolean EmuLoop(gpointer data) #ifdef HAVE_LIBAGG Hud.fps3d = GPU->GetFPSRender3D(); - if(nds.idleFrameCounter==0 || oneSecond) + if (nds.idleFrameCounter==0 || oneSecond) { u32 loadAvgARM9; u32 loadAvgARM7; @@ -3310,7 +3368,7 @@ common_gtk_main( class configured_features *my_config) slot2_device_type = NDS_SLOT2_NONE; break; } - + slot2_Init(); slot2_Change((NDS_SLOT2_TYPE)slot2_device_type); @@ -3338,15 +3396,15 @@ common_gtk_main( class configured_features *my_config) */ #ifdef GDB_STUB gdbstub_mutex_init(); - + gdbstub_handle_t arm9_gdb_stub = NULL; gdbstub_handle_t arm7_gdb_stub = NULL; - + if ( my_config->arm9_gdb_port > 0) { arm9_gdb_stub = createStub_gdb( my_config->arm9_gdb_port, &NDS_ARM9, &arm9_direct_memory_iface); - + if ( arm9_gdb_stub == NULL) { g_printerr("Failed to create ARM9 gdbstub on port %d\n", my_config->arm9_gdb_port); @@ -3360,7 +3418,7 @@ common_gtk_main( class configured_features *my_config) arm7_gdb_stub = createStub_gdb( my_config->arm7_gdb_port, &NDS_ARM7, &arm7_base_memory_iface); - + if ( arm7_gdb_stub == NULL) { g_printerr("Failed to create ARM7 gdbstub on port %d\n", my_config->arm7_gdb_port); @@ -3376,8 +3434,8 @@ common_gtk_main( class configured_features *my_config) if(!init_joy()) return 1; dTools_running = (BOOL*)malloc(sizeof(BOOL) * dTools_list_size); - if (dTools_running != NULL) - memset(dTools_running, FALSE, sizeof(BOOL) * dTools_list_size); + if (dTools_running != NULL) + memset(dTools_running, FALSE, sizeof(BOOL) * dTools_list_size); keyfile = desmume_config_read_file(gtk_kb_cfg); @@ -3421,21 +3479,21 @@ common_gtk_main( class configured_features *my_config) #endif desmume_gtk_menu_file_saveload_slot(action_group); desmume_gtk_menu_tools(action_group); - gtk_action_group_add_radio_actions(action_group, savet_entries, G_N_ELEMENTS(savet_entries), + gtk_action_group_add_radio_actions(action_group, savet_entries, G_N_ELEMENTS(savet_entries), my_config->savetype, G_CALLBACK(changesavetype), NULL); if (config.view_cairoFilter < CAIRO_FILTER_FAST || config.view_cairoFilter > CAIRO_FILTER_BILINEAR) { config.view_cairoFilter = CAIRO_FILTER_NEAREST; } Interpolation = (cairo_filter_t)config.view_cairoFilter.get(); - gtk_action_group_add_radio_actions(action_group, interpolation_entries, G_N_ELEMENTS(interpolation_entries), + gtk_action_group_add_radio_actions(action_group, interpolation_entries, G_N_ELEMENTS(interpolation_entries), Interpolation, G_CALLBACK(Modify_Interpolation), NULL); if (config.view_filter < VideoFilterTypeID_None || config.view_filter >= VideoFilterTypeIDCount) { config.view_filter = VideoFilterTypeID_None; } video->ChangeFilterByID((VideoFilterTypeID)config.view_filter.get()); - gtk_action_group_add_radio_actions(action_group, pri_interpolation_entries, G_N_ELEMENTS(pri_interpolation_entries), + gtk_action_group_add_radio_actions(action_group, pri_interpolation_entries, G_N_ELEMENTS(pri_interpolation_entries), config.view_filter, G_CALLBACK(Modify_PriInterpolation), NULL); switch (config.audio_sync) { @@ -3462,7 +3520,7 @@ common_gtk_main( class configured_features *my_config) gtk_action_group_add_radio_actions(action_group, spuinterpolation_entries, G_N_ELEMENTS(spuinterpolation_entries), CommonSettings.spuInterpolationMode, G_CALLBACK(Modify_SPUInterpolation), NULL); - gtk_action_group_add_radio_actions(action_group, frameskip_entries, G_N_ELEMENTS(frameskip_entries), + gtk_action_group_add_radio_actions(action_group, frameskip_entries, G_N_ELEMENTS(frameskip_entries), config.frameskip, G_CALLBACK(Modify_Frameskip), NULL); autoFrameskipMax = config.frameskip; gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "frameskipA"), config.autoframeskip); @@ -3485,7 +3543,7 @@ common_gtk_main( class configured_features *my_config) break; } nds_screen.rotation_angle = config.view_rot; - gtk_action_group_add_radio_actions(action_group, rotation_entries, G_N_ELEMENTS(rotation_entries), + gtk_action_group_add_radio_actions(action_group, rotation_entries, G_N_ELEMENTS(rotation_entries), nds_screen.rotation_angle, G_CALLBACK(SetRotation), NULL); @@ -3493,14 +3551,14 @@ common_gtk_main( class configured_features *my_config) config.window_scale = WINSIZE_SCALE; } winsize_current = (winsize_enum)config.window_scale.get(); - gtk_action_group_add_radio_actions(action_group, winsize_entries, G_N_ELEMENTS(winsize_entries), + gtk_action_group_add_radio_actions(action_group, winsize_entries, G_N_ELEMENTS(winsize_entries), winsize_current, G_CALLBACK(SetWinsize), NULL); if (config.view_orient < ORIENT_VERTICAL || config.view_orient > ORIENT_SINGLE) { config.view_orient = ORIENT_VERTICAL; } nds_screen.orientation = (orientation_enum)config.view_orient.get(); - gtk_action_group_add_radio_actions(action_group, orientation_entries, G_N_ELEMENTS(orientation_entries), + gtk_action_group_add_radio_actions(action_group, orientation_entries, G_N_ELEMENTS(orientation_entries), nds_screen.orientation, G_CALLBACK(SetOrientation), NULL); { @@ -3521,7 +3579,7 @@ common_gtk_main( class configured_features *my_config) gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "orient_swapscreens"), config.view_swap); gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - + accel_group = gtk_ui_manager_get_accel_group (ui_manager); gtk_window_add_accel_group (GTK_WINDOW (pWindow), accel_group); @@ -3608,22 +3666,60 @@ common_gtk_main( class configured_features *my_config) gtk_toggle_action_set_active((GtkToggleAction *)action, FALSE); } -#if defined(HAVE_OPENGL) && defined(OGLRENDER_3_2_H) +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) + #if defined(OGLRENDER_3_2_H) OGLLoadEntryPoints_3_2_Func = OGLLoadEntryPoints_3_2; OGLCreateRenderer_3_2_Func = OGLCreateRenderer_3_2; -#endif + #endif + #if defined(OGLRENDER_ES3_H) + OGLLoadEntryPoints_ES_3_0_Func = &OGLLoadEntryPoints_ES_3_0; + OGLCreateRenderer_ES_3_0_Func = &OGLCreateRenderer_ES_3_0; + #endif + + #if defined(ENABLE_GLX) + oglrender_init = &glx_initOpenGL_StandardAuto; + oglrender_deinit = &glx_deinitOpenGL; + oglrender_beginOpenGL = &glx_beginOpenGL; + oglrender_endOpenGL = &glx_endOpenGL; + oglrender_framebufferDidResizeCallback = &glx_framebufferDidResizeCallback; + #elif defined(ENABLE_OSMESA) + oglrender_init = &osmesa_initOpenGL_StandardAuto; + oglrender_deinit = &osmesa_deinitOpenGL; + oglrender_beginOpenGL = &osmesa_beginOpenGL; + oglrender_endOpenGL = &osmesa_endOpenGL; + oglrender_framebufferDidResizeCallback = &osmesa_framebufferDidResizeCallback; + #elif defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_StandardAuto; + oglrender_deinit = &egl_deinitOpenGL; + oglrender_beginOpenGL = &egl_beginOpenGL; + oglrender_endOpenGL = &egl_endOpenGL; + oglrender_framebufferDidResizeCallback = &egl_framebufferDidResizeCallback; + #else + oglrender_init = &sdl_initOpenGL_StandardAuto; + oglrender_deinit = &sdl_deinitOpenGL; + oglrender_beginOpenGL = &sdl_beginOpenGL; + oglrender_endOpenGL = &sdl_endOpenGL; + oglrender_framebufferDidResizeCallback = &sdl_framebufferDidResizeCallback; + #endif +#endif // ENABLE_OPENGL_STANDARD || ENABLE_OPENGL_ES //Set the 3D emulation to use int core = my_config->engine_3d; // setup the gdk 3D emulation; // Check if commandLine argument was passed or not - if (core == -1) { + if (core == -1) + { // If it was not passed, then get the Renderer config from the file core = config.core3D; // Check if it is valid - if (!(core >= 0 && core <= 2)) { +#if defined(ENABLE_OPENGL_ES) + if (!(core >= 0 && core <= 2)) +#elif defined(ENABLE_OPENGL_STANDARD) + if (!(core >= 0 && core <= 4)) +#endif + { // If it is invalid, reset it to SoftRasterizer core = 1; } @@ -3631,21 +3727,65 @@ common_gtk_main( class configured_features *my_config) my_config->engine_3d = core; } - if (core == 2) + switch (core) { -#if !defined(HAVE_OPENGL) - core = RENDERID_SOFTRASTERIZER; -#elif defined(HAVE_LIBOSMESA) - if (!is_osmesa_initialized()) - { - init_osmesa_3Demu(); - } -#else - if (!is_sdl_initialized()) +#if defined(ENABLE_OPENGL_ES) && !defined(ENABLE_OSMESA) && !defined(ENABLE_GLX) + case 2: + #if defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_ES_3_0; + #else + oglrender_init = &sdl_initOpenGL_ES_3_0; + #endif + break; +#elif defined(ENABLE_OPENGL_STANDARD) + case 2: + #if defined(ENABLE_GLX) + oglrender_init = &glx_initOpenGL_StandardAuto; + #elif defined(ENABLE_OSMESA) + oglrender_init = &osmesa_initOpenGL_StandardAuto; + #elif defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_StandardAuto; + #else + oglrender_init = &sdl_initOpenGL_StandardAuto; + #endif + break; + + case 3: + #if defined(ENABLE_GLX) + oglrender_init = &glx_initOpenGL_LegacyAuto; + #elif defined(ENABLE_OSMESA) + oglrender_init = &osmesa_initOpenGL_LegacyAuto; + #elif defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_LegacyAuto; + #else + oglrender_init = &sdl_initOpenGL_LegacyAuto; + #endif + break; + + case 4: + #if defined(ENABLE_GLX) + oglrender_init = &glx_initOpenGL_3_2_CoreProfile; + #elif defined(ENABLE_OSMESA) + oglrender_init = &osmesa_initOpenGL_3_2_CoreProfile; + #elif defined(ENABLE_EGL) + oglrender_init = &egl_initOpenGL_3_2_CoreProfile; + #else + oglrender_init = &sdl_initOpenGL_3_2_CoreProfile; + #endif + break; +#endif + default: { - init_sdl_3Demu(); + if (core > 0) + { + core = RENDERID_SOFTRASTERIZER; + } + else + { + core = RENDERID_NULL; + } + break; } -#endif } if (!GPU->Change3DRendererByID(core)) { @@ -3667,7 +3807,7 @@ common_gtk_main( class configured_features *my_config) backup_setManualBackupType(my_config->savetype); - // Command line arg + // Command line arg if( my_config->nds_file != "") { if(Open( my_config->nds_file.c_str()) >= 0) { my_config->process_movieCommands(); @@ -3715,11 +3855,17 @@ common_gtk_main( class configured_features *my_config) desmume_free(); -#if defined(HAVE_LIBOSMESA) - deinit_osmesa_3Demu(); -#else - deinit_sdl_3Demu(); -#endif +#if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) + #if defined(ENABLE_GLX) + glx_deinitOpenGL(); + #elif defined(ENABLE_OSMESA) + osmesa_deinitOpenGL(); + #elif defined(ENABLE_EGL) + egl_deinitOpenGL(); + #else + sdl_deinitOpenGL(); + #endif +#endif // ENABLE_OPENGL_STANDARD || ENABLE_OPENGL_ES /* Unload joystick */ uninit_joy(); diff --git a/desmume/src/frontend/posix/gtk2/meson.build b/desmume/src/frontend/posix/gtk2/meson.build index 25aa124b8..8420302d2 100644 --- a/desmume/src/frontend/posix/gtk2/meson.build +++ b/desmume/src/frontend/posix/gtk2/meson.build @@ -4,21 +4,43 @@ dep_x11 = dependency('x11') gtk_dependencies = dependencies + [dep_gtk3, dep_x11] desmume_src = [ - 'avout_pipe_base.cpp', - 'avout_x264.cpp', - 'avout_flac.cpp', + '../shared/avout_flac.cpp', + '../shared/avout_pipe_base.cpp', + '../shared/avout_x264.cpp', + '../shared/ctrlssdl.cpp', + '../shared/sndsdl.cpp', 'config.cpp', 'desmume.cpp', 'dToolsList.cpp', 'tools/ioregsView.cpp', - '../shared/sndsdl.cpp', - '../shared/ctrlssdl.cpp', - 'osmesa_3Demu.cpp', - 'sdl_3Demu.cpp', 'cheatsGTK.cpp', 'main.cpp', ] +if get_option('glx') and dep_glx.found() + add_global_arguments('-DENABLE_GLX', language: ['c', 'cpp']) + dependencies += dep_glx + desmume_src += [ + '../shared/glx_3Demu.cpp', + ] +elif get_option('osmesa') and dep_osmesa.found() + add_global_arguments('-DENABLE_OSMESA', language: ['c', 'cpp']) + dependencies += dep_osmesa + desmume_src += [ + '../shared/osmesa_3Demu.cpp', + ] +elif get_option('egl') and dep_egl.found() + add_global_arguments('-DENABLE_EGL', language: ['c', 'cpp']) + dependencies += dep_egl + desmume_src += [ + '../shared/egl_3Demu.cpp', + ] +else + desmume_src += [ + '../shared/sdl_3Demu.cpp', + ] +endif + # TODO: why do we have to redeclare it here with one more fs level? includes = include_directories( '../../../../src', diff --git a/desmume/src/frontend/posix/gtk2/osmesa_3Demu.cpp b/desmume/src/frontend/posix/gtk2/osmesa_3Demu.cpp deleted file mode 100644 index 78bf89a2e..000000000 --- a/desmume/src/frontend/posix/gtk2/osmesa_3Demu.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - Copyright (C) 2009 Guillaume Duhamel - Copyright (C) 2009-2024 DeSmuME team - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the this software. If not, see . - */ - -#ifdef HAVE_LIBOSMESA - -#include -#include -#include "../OGLRender_3_2.h" - -#include "osmesa_3Demu.h" - -static void *buffer = NULL; -static OSMesaContext ctx = NULL; - -static bool osmesa_beginOpenGL(void) { return 1; } -static void osmesa_endOpenGL(void) { } -static bool osmesa_init(void) { return is_osmesa_initialized(); } - -void deinit_osmesa_3Demu (void) -{ - free(buffer); - buffer = NULL; - - OSMesaDestroyContext(ctx); - ctx = NULL; -} - -bool init_osmesa_3Demu(void) -{ -#if (((OSMESA_MAJOR_VERSION * 100) + OSMESA_MINOR_VERSION) >= 1102) && defined(OSMESA_CONTEXT_MAJOR_VERSION) - static const int attributes_3_2_core_profile[] = { - OSMESA_FORMAT, OSMESA_RGBA, - OSMESA_DEPTH_BITS, 24, - OSMESA_STENCIL_BITS, 8, - OSMESA_ACCUM_BITS, 0, - OSMESA_PROFILE, OSMESA_CORE_PROFILE, - OSMESA_CONTEXT_MAJOR_VERSION, 3, - OSMESA_CONTEXT_MINOR_VERSION, 2, - 0 }; - - ctx = OSMesaCreateContextAttribs(attributes_3_2_core_profile, NULL); - if (ctx == NULL) - { - printf("OSMesa: Could not create a 3.2 Core Profile context. Will attempt to create a 2.1 compatibility context...\n"); - - static const int attributes_2_1[] = { - OSMESA_FORMAT, OSMESA_RGBA, - OSMESA_DEPTH_BITS, 24, - OSMESA_STENCIL_BITS, 8, - OSMESA_ACCUM_BITS, 0, - OSMESA_PROFILE, OSMESA_COMPAT_PROFILE, - OSMESA_CONTEXT_MAJOR_VERSION, 2, - OSMESA_CONTEXT_MINOR_VERSION, 1, - 0 }; - - ctx = OSMesaCreateContextAttribs(attributes_2_1, NULL); - } -#endif - - if (ctx == NULL) - { - ctx = OSMesaCreateContextExt(OSMESA_RGBA, 24, 8, 0, NULL); - if (ctx == NULL) - { - printf("OSMesa: OSMesaCreateContextExt() failed!\n"); - return false; - } - } - - buffer = malloc(GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(uint32_t)); - if (!buffer) - { - printf("OSMesa: Could not allocate enough memory for the context!\n"); - return false; - } - - if (!OSMesaMakeCurrent(ctx, buffer, GL_UNSIGNED_BYTE, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT)) - { - printf("OSMesa: OSMesaMakeCurrent() failed!\n"); - free(buffer); - return false; - } - - oglrender_init = osmesa_init; - oglrender_beginOpenGL = osmesa_beginOpenGL; - oglrender_endOpenGL = osmesa_endOpenGL; - - return true; -} - -bool is_osmesa_initialized(void) -{ - return (ctx != NULL); -} - -#endif diff --git a/desmume/src/frontend/posix/gtk2/sdl_3Demu.cpp b/desmume/src/frontend/posix/gtk2/sdl_3Demu.cpp deleted file mode 100644 index fb05b157c..000000000 --- a/desmume/src/frontend/posix/gtk2/sdl_3Demu.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - Copyright (C) 2020 Emmanuel Gil Peyrot - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the this software. If not, see . - */ - -#include -#include -#include "../OGLRender.h" - -#include "sdl_3Demu.h" - -static bool sdl_beginOpenGL(void) { return 1; } -static void sdl_endOpenGL(void) { } -static bool sdl_init(void) { return is_sdl_initialized(); } - -static SDL_Window *win = NULL; -static SDL_GLContext ctx = NULL; - -bool deinit_sdl_3Demu(void) -{ - bool ret = false; - - if (ctx) { - SDL_GL_DeleteContext(ctx); - ctx = NULL; - ret = true; - } - - if (win) { - SDL_DestroyWindow(win); - win = NULL; - ret = true; - } - - return ret; -} - -bool init_sdl_3Demu(void) -{ - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); - - win = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 256, 192, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN); - if (!win) { - fprintf(stderr, "SDL: Failed to create a window: %s\n", SDL_GetError()); - return false; - } - - ctx = SDL_GL_CreateContext(win); - if (!ctx) { - fprintf(stderr, "SDL: Failed to create an OpenGL context: %s\n", SDL_GetError()); - return false; - } - - printf("OGL/SDL Renderer has finished the initialization.\n"); - - oglrender_init = sdl_init; - oglrender_beginOpenGL = sdl_beginOpenGL; - oglrender_endOpenGL = sdl_endOpenGL; - - return true; -} - -bool is_sdl_initialized(void) -{ - return (ctx != NULL); -} diff --git a/desmume/src/frontend/posix/meson.build b/desmume/src/frontend/posix/meson.build index 13bf45a25..3280842b4 100644 --- a/desmume/src/frontend/posix/meson.build +++ b/desmume/src/frontend/posix/meson.build @@ -16,11 +16,15 @@ dep_pcap = dependency('pcap') dep_zlib = dependency('zlib') dep_threads = dependency('threads') dep_gl = dependency('gl', required: false) +dep_gles = dependency('glesv2', required: false) dep_openal = dependency('openal', required: get_option('openal')) dep_alsa = dependency('alsa', required: false) dep_soundtouch = dependency('soundtouch', required: false) dep_agg = dependency('libagg', required: false) dep_fontconfig = dependency('fontconfig', required: false) +dep_glx = dependency('glx', required: false) +dep_osmesa = dependency('osmesa', required: false) +dep_egl = dependency('egl', required: false) # XXX: something wrong with this one. #dep_lua = dependency('lua-5.1', required: false) @@ -168,12 +172,65 @@ libdesmume_src += [ 'shared/desmume_config.cpp', ] -if dep_gl.found() - dependencies += dep_gl - libdesmume_src += [ - '../../OGLRender.cpp', - '../../OGLRender_3_2.cpp', - ] +if get_option('opengles') + if dep_gles.found() + add_global_arguments('-DENABLE_OPENGL_ES', language: ['c', 'cpp']) + dependencies += dep_gles + libdesmume_src += [ + '../../OGLRender.cpp', + '../../OGLRender_3_2.cpp', + '../../OGLRender_ES3.cpp', + ] + else + message('Cannot build with OpenGL ES -- glesv2 library not found.') + endif +elif get_option('opengl') + if dep_gl.found() + add_global_arguments('-DENABLE_OPENGL_STANDARD', language: ['c', 'cpp']) + dependencies += dep_gl + libdesmume_src += [ + '../../OGLRender.cpp', + '../../OGLRender_3_2.cpp', + ] + else + message('Cannot build with OpenGL -- gl library not found.') + endif +endif + +if get_option('glx') + if dep_glx.found() + if get_option('opengl') and dep_gl.found() + add_global_arguments('-DENABLE_GLX', language: ['c', 'cpp']) + dependencies += dep_glx + elif get_option('opengles') + message('GLX contexts are incompatible with OpenGL ES -- cancelling the use of GLX.') + else + message('GLX contexts are only compatible with standard OpenGL -- cancelling the use of GLX.') + endif + else + message('Cannot use GLX -- glx library not found.') + endif +elif get_option('osmesa') + if dep_osmesa.found() + if get_option('opengl') and dep_gl.found() + message('OSMesa contexts are deprecated.') + add_global_arguments('-DENABLE_OSMESA', language: ['c', 'cpp']) + dependencies += dep_osmesa + elif get_option('opengles') + message('OSMesa contexts are incompatible with OpenGL ES -- cancelling the use of OSMesa.') + else + message('OSMesa contexts are only compatible with standard OpenGL -- cancelling the use of OSMesa.') + endif + else + message('Cannot use OSMesa -- osmesa library not found.') + endif +elif get_option('egl') + if dep_egl.found() + add_global_arguments('-DENABLE_EGL', language: ['c', 'cpp']) + dependencies += dep_egl + else + message('Cannot use EGL -- egl library not found.') + endif endif if dep_openal.found() diff --git a/desmume/src/frontend/posix/meson_options.txt b/desmume/src/frontend/posix/meson_options.txt index 1deece7f0..bbe866a21 100644 --- a/desmume/src/frontend/posix/meson_options.txt +++ b/desmume/src/frontend/posix/meson_options.txt @@ -1,3 +1,28 @@ +option('opengl', + type: 'boolean', + value: false, + description: 'Build for OpenGL', +) +option('opengles', + type: 'boolean', + value: false, + description: 'Build for OpenGL ES', +) +option('glx', + type: 'boolean', + value: false, + description: 'Use a GLX context', +) +option('osmesa', + type: 'boolean', + value: false, + description: 'Use a OSMesa context', +) +option('egl', + type: 'boolean', + value: false, + description: 'Use a EGL context', +) option('openal', type: 'boolean', value: false, diff --git a/desmume/src/frontend/posix/gtk/avout.h b/desmume/src/frontend/posix/shared/avout.h similarity index 100% rename from desmume/src/frontend/posix/gtk/avout.h rename to desmume/src/frontend/posix/shared/avout.h diff --git a/desmume/src/frontend/posix/gtk/avout_flac.cpp b/desmume/src/frontend/posix/shared/avout_flac.cpp similarity index 100% rename from desmume/src/frontend/posix/gtk/avout_flac.cpp rename to desmume/src/frontend/posix/shared/avout_flac.cpp diff --git a/desmume/src/frontend/posix/gtk/avout_flac.h b/desmume/src/frontend/posix/shared/avout_flac.h similarity index 100% rename from desmume/src/frontend/posix/gtk/avout_flac.h rename to desmume/src/frontend/posix/shared/avout_flac.h diff --git a/desmume/src/frontend/posix/gtk/avout_pipe_base.cpp b/desmume/src/frontend/posix/shared/avout_pipe_base.cpp similarity index 100% rename from desmume/src/frontend/posix/gtk/avout_pipe_base.cpp rename to desmume/src/frontend/posix/shared/avout_pipe_base.cpp diff --git a/desmume/src/frontend/posix/gtk/avout_pipe_base.h b/desmume/src/frontend/posix/shared/avout_pipe_base.h similarity index 100% rename from desmume/src/frontend/posix/gtk/avout_pipe_base.h rename to desmume/src/frontend/posix/shared/avout_pipe_base.h diff --git a/desmume/src/frontend/posix/gtk/avout_x264.cpp b/desmume/src/frontend/posix/shared/avout_x264.cpp similarity index 100% rename from desmume/src/frontend/posix/gtk/avout_x264.cpp rename to desmume/src/frontend/posix/shared/avout_x264.cpp diff --git a/desmume/src/frontend/posix/gtk/avout_x264.h b/desmume/src/frontend/posix/shared/avout_x264.h similarity index 100% rename from desmume/src/frontend/posix/gtk/avout_x264.h rename to desmume/src/frontend/posix/shared/avout_x264.h diff --git a/desmume/src/frontend/posix/shared/egl_3Demu.cpp b/desmume/src/frontend/posix/shared/egl_3Demu.cpp new file mode 100644 index 000000000..f15e2b428 --- /dev/null +++ b/desmume/src/frontend/posix/shared/egl_3Demu.cpp @@ -0,0 +1,357 @@ +/* + Copyright (C) 2024 DeSmuME team + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the this software. If not, see . +*/ + +#include +#include +#include +#include + +#include "egl_3Demu.h" +#include "OGLRender_3_2.h" + + +static EGLDisplay currDisplay = EGL_NO_DISPLAY; +static EGLSurface currSurface = EGL_NO_SURFACE; +static EGLContext currContext = EGL_NO_CONTEXT; + +static EGLDisplay prevDisplay = EGL_NO_DISPLAY; +static EGLSurface prevDrawSurface = EGL_NO_SURFACE; +static EGLSurface prevReadSurface = EGL_NO_SURFACE; +static EGLContext prevContext = EGL_NO_CONTEXT; + +static EGLSurface pendingSurface = EGL_NO_SURFACE; +static EGLint *lastConfigAttr = NULL; + +static bool __egl_initOpenGL(const int requestedAPI, const int requestedProfile, const int requestedVersionMajor, const int requestedVersionMinor) +{ + if (currContext != EGL_NO_CONTEXT) + { + return true; + } + + EGLint eglMajorVersion; + EGLint eglMinorVersion; + + currDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (eglInitialize(currDisplay, &eglMajorVersion, &eglMinorVersion) == EGL_FALSE) + { + puts("EGL: eglInitialize failed"); + return false; + } + + // Our EGL context requires the following features: + // - EGL_OPENGL_ES3_BIT for EGL_RENDERABLE_TYPE + // - EGL_KHR_surfaceless_context + if ( (eglMajorVersion <= 1) && (eglMinorVersion < 5) ) + { + if (eglMinorVersion < 4) + { + eglTerminate(currDisplay); + printf("EGL: Requires EGL v1.4 or later. Your EGL version (v%i.%i) is too old.\n", (int)eglMajorVersion, (int)eglMinorVersion); + return false; + } + + const char *extensionSet = eglQueryString(currDisplay, EGL_EXTENSIONS); + + const char *foundString = strstr(extensionSet, "EGL_KHR_create_context"); + if (foundString == NULL) + { + eglTerminate(currDisplay); + puts("EGL: OpenGL ES 3.0 context creation is not available."); + return false; + } + + foundString = strstr(extensionSet, "EGL_KHR_surfaceless_context"); + if (foundString == NULL) + { + eglTerminate(currDisplay); + puts("EGL: EGL_KHR_surfaceless_context is a required extension."); + return false; + } + } + + // EGL config attributes, initially set up for standard OpenGL running in legacy mode + EGLint confAttr[] = { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_DEPTH_SIZE, 24, + EGL_STENCIL_SIZE, 8, + EGL_NONE + }; + + if ( (requestedAPI == EGL_OPENGL_API) && (requestedProfile == EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR) ) + { + confAttr[8] = EGL_NONE; + confAttr[9] = EGL_NONE; + + confAttr[10] = EGL_NONE; + confAttr[11] = EGL_NONE; + + confAttr[12] = EGL_NONE; + confAttr[13] = EGL_NONE; + } + else if (requestedAPI == EGL_OPENGL_ES_API) + { + confAttr[8] = EGL_RENDERABLE_TYPE; + confAttr[9] = EGL_OPENGL_ES3_BIT_KHR; + + confAttr[10] = EGL_NONE; + confAttr[11] = EGL_NONE; + + confAttr[12] = EGL_NONE; + confAttr[13] = EGL_NONE; + } + + // choose the first config, i.e. best config + EGLConfig eglConf; + EGLint numConfigs; + eglChooseConfig(currDisplay, confAttr, &eglConf, 1, &numConfigs); + if (numConfigs < 1) + { + eglTerminate(currDisplay); + puts("EGL: eglChooseConfig failed"); + return false; + } + + // Make a copy of the last working config attributes for legacy OpenGL running + // the default framebuffer. + if (lastConfigAttr == NULL) + { + lastConfigAttr = (EGLint *)malloc(sizeof(confAttr)); + } + memcpy(lastConfigAttr, confAttr, sizeof(confAttr)); + + eglBindAPI(requestedAPI); + + // EGL context attributes + const EGLint ctxAttr[] = { + EGL_CONTEXT_MAJOR_VERSION_KHR, requestedVersionMajor, + EGL_CONTEXT_MINOR_VERSION_KHR, requestedVersionMinor, + (requestedAPI == EGL_OPENGL_ES_API) ? EGL_NONE : EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, requestedProfile, + EGL_NONE + }; + + currContext = eglCreateContext(currDisplay, eglConf, EGL_NO_CONTEXT, ctxAttr); + if (currContext == EGL_NO_CONTEXT) + { + eglTerminate(currDisplay); + puts("EGL: eglCreateContext failed"); + return false; + } + + if (requestedProfile == EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR) + { + // Do note that P-Buffer creation has to occur after context creation + // since P-Buffers are dependent on a context with EGL_PBUFFER_BIT as + // its EGL_SURFACE_TYPE. + const EGLint pbufferAttr[] = { + EGL_WIDTH, (EGLint)GPU_FRAMEBUFFER_NATIVE_WIDTH, + EGL_HEIGHT, (EGLint)GPU_FRAMEBUFFER_NATIVE_HEIGHT, + EGL_NONE + }; + + currSurface = eglCreatePbufferSurface(currDisplay, eglConf, pbufferAttr); + if (currSurface == EGL_NO_SURFACE) + { + puts("EGL: eglCreatePbufferSurface failed"); + return false; + } + } + + puts("EGL: OpenGL context creation successful."); + return true; +} + +bool egl_initOpenGL_StandardAuto() +{ + bool isContextCreated = egl_initOpenGL_3_2_CoreProfile(); + + if (!isContextCreated) + { + isContextCreated = egl_initOpenGL_LegacyAuto(); + } + + return isContextCreated; +} + +bool egl_initOpenGL_LegacyAuto() +{ + return __egl_initOpenGL(EGL_OPENGL_API, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR, 1, 2); +} + +bool egl_initOpenGL_3_2_CoreProfile() +{ + return __egl_initOpenGL(EGL_OPENGL_API, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, 3, 2); +} + +bool egl_initOpenGL_ES_3_0() +{ + return __egl_initOpenGL(EGL_OPENGL_ES_API, EGL_NONE, 3, 0); +} + +void egl_deinitOpenGL() +{ + if (currDisplay == EGL_NO_DISPLAY) + { + return; + } + + eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(currDisplay, currContext); + + if (currSurface != EGL_NO_SURFACE) + { + eglDestroySurface(currDisplay, currSurface); + } + + eglTerminate(currDisplay); + + if (lastConfigAttr == NULL) + { + free(lastConfigAttr); + lastConfigAttr = NULL; + } + + currContext = EGL_NO_CONTEXT; + currSurface = EGL_NO_SURFACE; + currDisplay = EGL_NO_DISPLAY; + + prevDisplay = EGL_NO_DISPLAY; + prevDrawSurface = EGL_NO_SURFACE; + prevReadSurface = EGL_NO_SURFACE; + prevContext = EGL_NO_CONTEXT; +} + +bool egl_beginOpenGL() +{ + EGLBoolean ret = EGL_FALSE; + + prevDisplay = eglGetCurrentDisplay(); + prevDrawSurface = eglGetCurrentSurface(0); + prevReadSurface = eglGetCurrentSurface(1); + prevContext = eglGetCurrentContext(); + + if (pendingSurface != EGL_NO_SURFACE) + { + bool previousIsCurrent = (prevDrawSurface == currSurface); + + ret = eglMakeCurrent(currDisplay, pendingSurface, pendingSurface, currContext); + if (ret == EGL_TRUE) + { + eglDestroySurface(currDisplay, currSurface); + currSurface = pendingSurface; + + if (previousIsCurrent) + { + prevDrawSurface = currSurface; + prevReadSurface = currSurface; + } + + pendingSurface = EGL_NO_SURFACE; + } + } + else + { + ret = eglMakeCurrent(currDisplay, currSurface, currSurface, currContext); + } + + return (ret == EGL_TRUE); +} + +void egl_endOpenGL() +{ + if (prevDisplay == EGL_NO_DISPLAY) + { + prevDisplay = currDisplay; + } + + if (prevContext == EGL_NO_CONTEXT) + { + prevContext = currContext; + } + + if (prevDrawSurface == EGL_NO_SURFACE) + { + prevDrawSurface = currSurface; + } + + if (prevReadSurface == EGL_NO_SURFACE) + { + prevReadSurface = currSurface; + } + + if ( (prevDisplay != currDisplay) || + (prevContext != currContext) || + (prevDrawSurface != currSurface) || + (prevReadSurface != currSurface) ) + { + eglMakeCurrent(prevDisplay, prevDrawSurface, prevReadSurface, prevContext); + } +} + +bool egl_framebufferDidResizeCallback(bool isFBOSupported, size_t w, size_t h) +{ + bool result = false; + + if (isFBOSupported) + { + result = true; + return result; + } + + EGLint currWidth; + EGLint currHeight; + eglQuerySurface(currDisplay, currSurface, EGL_WIDTH, &currWidth); + eglQuerySurface(currDisplay, currSurface, EGL_HEIGHT, &currHeight); + + if ( (w == (size_t)currWidth) && (h == (size_t)currHeight) ) + { + result = true; + return result; + } + + if (pendingSurface != EGL_NO_SURFACE) + { + // Destroy any existing pending surface now since we need it to + // always have the lastest framebuffer size. + eglDestroySurface(currDisplay, pendingSurface); + } + + // choose the first config, i.e. best config + EGLConfig eglConf; + EGLint numConfigs; + eglChooseConfig(currDisplay, lastConfigAttr, &eglConf, 1, &numConfigs); + + const EGLint pbufferAttr[] = { + EGL_WIDTH, (EGLint)w, + EGL_HEIGHT, (EGLint)h, + EGL_NONE + }; + + pendingSurface = eglCreatePbufferSurface(currDisplay, eglConf, pbufferAttr); + if (pendingSurface == EGL_NO_SURFACE) + { + puts("EGL: eglCreatePbufferSurface failed"); + return result; + } + + result = true; + return result; +} diff --git a/desmume/src/frontend/posix/gtk2/avout_x264.h b/desmume/src/frontend/posix/shared/egl_3Demu.h similarity index 61% rename from desmume/src/frontend/posix/gtk2/avout_x264.h rename to desmume/src/frontend/posix/shared/egl_3Demu.h index 24125a0f9..b9775516c 100644 --- a/desmume/src/frontend/posix/gtk2/avout_x264.h +++ b/desmume/src/frontend/posix/shared/egl_3Demu.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014 DeSmuME team + Copyright (C) 2024 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,20 +15,17 @@ along with the this software. If not, see . */ -#ifndef _AVOUT_X264_H_ -#define _AVOUT_X264_H_ +#ifndef __EGL_3DEMU_H__ +#define __EGL_3DEMU_H__ -#include "avout_pipe_base.h" +bool egl_initOpenGL_StandardAuto(); +bool egl_initOpenGL_LegacyAuto(); +bool egl_initOpenGL_3_2_CoreProfile(); +bool egl_initOpenGL_ES_3_0(); -class AVOutX264 : public AVOutPipeBase { -public: - AVOutX264(); -protected: - Type type() { return TYPE_VIDEO; } - const char* const* getArgv(const char* fname); -private: - char filename[1024]; - const char* args[19]; -}; +void egl_deinitOpenGL(); +bool egl_beginOpenGL(); +void egl_endOpenGL(); +bool egl_framebufferDidResizeCallback(bool isFBOSupported, size_t w, size_t h); -#endif +#endif // __EGL_3DEMU_H__ diff --git a/desmume/src/frontend/posix/shared/glx_3Demu.cpp b/desmume/src/frontend/posix/shared/glx_3Demu.cpp new file mode 100644 index 000000000..71b3dee2a --- /dev/null +++ b/desmume/src/frontend/posix/shared/glx_3Demu.cpp @@ -0,0 +1,370 @@ +/* + Copyright (C) 2024 DeSmuME team + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the this software. If not, see . +*/ + +#include +#include +#include +#include +#include +#include + +#include "glx_3Demu.h" + + +static Display *currDisplay = NULL; +static GLXDrawable currDrawable = 0; +static GLXContext currContext = NULL; + +static Display *prevDisplay = NULL; +static GLXDrawable prevDrawDrawable = 0; +static GLXDrawable prevReadDrawable = 0; +static GLXContext prevContext = NULL; + +static GLXDrawable pendingDrawable = 0; + +static GLXFBConfig bestFBConfig = NULL; + +static bool didErrorOccur = false; + +static int __GLXContextErrorHandler(Display *dpy, XErrorEvent *ev) +{ + didErrorOccur = true; + return 0; +} + +static void __GLXCurrentDisplayClose() +{ + if (currDisplay == NULL) + { + return; + } + + XCloseDisplay(currDisplay); + currDisplay = NULL; +} + +static bool __glx_initOpenGL(const int requestedProfile, const int requestedVersionMajor, const int requestedVersionMinor) +{ + if (currContext != NULL) + { + return true; + } + + currDisplay = XOpenDisplay(NULL); + + int currScreen = DefaultScreen(currDisplay); + int glxMajorVersion = 0; + int glxMinorVersion = 0; + + if (glXQueryVersion(currDisplay, &glxMajorVersion, &glxMinorVersion) == False) + { + __GLXCurrentDisplayClose(); + puts("GLX: glXQueryVersion failed"); + return false; + } + + // Our GLX context requires the following features: + // - GLX_ARB_create_context_profile + PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = NULL; + + if ( (glxMajorVersion >= 2) || ((glxMajorVersion == 1) && (glxMinorVersion >= 4)) ) + { + const char *extensionSet = glXQueryExtensionsString(currDisplay, currScreen); + + const char *foundString = strstr(extensionSet, "GLX_ARB_create_context_profile"); + glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB"); + + if ( (foundString == NULL) || (glXCreateContextAttribsARB == NULL) ) + { + __GLXCurrentDisplayClose(); + puts("GLX: OpenGL context creation is not available."); + return false; + } + } + else + { + __GLXCurrentDisplayClose(); + printf("GLX: Requires GLX v1.4 or later. Your GLX version (v%i.%i) is too old.\n", (int)glxMajorVersion, (int)glxMinorVersion); + return false; + } + + // Begin the process of searching for the best framebuffer configuration. + // This will be needed for creating the context and other related things. + int fbConfigAttr[] = { + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, + GLX_DEPTH_SIZE, 24, + GLX_STENCIL_SIZE, 8, + 0 + }; + + if (requestedProfile == GLX_CONTEXT_CORE_PROFILE_BIT_ARB) + { + // 3.2 Core Profile always uses FBOs, and so no P-Buffers, depth + // buffers, or stencil buffers are needed for this kind of context. + confAttr[10] = 0; + confAttr[11] = 0; + + confAttr[12] = 0; + confAttr[13] = 0; + + confAttr[14] = 0; + confAttr[15] = 0; + } + + int fbConfigCount = 0; + GLXFBConfig *fbConfigList = glXChooseFBConfig(currDisplay, currScreen, fbConfigAttr, &fbConfigCount); + if ( (fbConfigList == NULL) || (fbConfigCount < 1) ) + { + __GLXCurrentDisplayClose(); + puts("GLX: glXChooseFBConfig found no configs"); + return false; + } + + int bestFBConfigIndex = -1; + int bestNumSamples = -1; + int configHasMultisamples = 0; + int numSamples = 0; + + // Discover the best framebuffer config for multisampled rendering on the + // default framebuffer. This isn't needed if we're running FBOs, but is + // needed for legacy OpenGL without FBO support. + for (int i = 0; i < fbConfigCount; i++) + { + XVisualInfo *vi = glXGetVisualFromFBConfig(currDisplay, fbConfigList[i]); + + if (vi != NULL) + { + glXGetFBConfigAttrib(currDisplay, fbConfigList[i], GLX_SAMPLE_BUFFERS, &configHasMultisamples); + glXGetFBConfigAttrib(currDisplay, fbConfigList[i], GLX_SAMPLES, &numSamples); + + if ( ((bestFBConfigIndex < 0) || configHasMultisamples) && (numSamples > bestNumSamples) ) + { + bestFBConfigIndex = i; + bestNumSamples = numSamples; + } + + XFree(vi); + } + } + + bestFBConfig = fbConfigList[bestFBConfigIndex]; + XFree(fbConfigList); + + if (requestedProfile == GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB) + { + const int pbufferAttr[] = { + GLX_PBUFFER_WIDTH, 256, + GLX_PBUFFER_HEIGHT, 192, + 0 + }; + + currDrawable = glXCreatePbuffer(currDisplay, bestFBConfig, pbufferAttr); + } + + // Install an X error handler so the application won't exit if GL 3.0 + // context allocation fails. + // + // Note this error handler is global. All display connections in all threads + // of a process use the same error handler, so be sure to guard against other + // threads issuing X commands while this code is running. + didErrorOccur = false; + int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&__GLXContextErrorHandler); + + // GLX context attributes + const int ctxAttr[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, requestedVersionMajor, + GLX_CONTEXT_MINOR_VERSION_ARB, requestedVersionMinor, + GLX_CONTEXT_PROFILE_MASK_ARB, requestedProfile, + 0 + }; + + currContext = glXCreateContextAttribsARB(currDisplay, bestFBConfig, NULL, True, ctxAttr); + + XSync(currDisplay, False); // Sync to ensure any errors generated are processed. + XSetErrorHandler(oldHandler); // Restore the original error handler + + if (didErrorOccur || (currContext == NULL)) + { + __GLXCurrentDisplayClose(); + puts("GLX: glXCreateContextAttribsARB failed"); + return false; + } + + puts("GLX: OpenGL context creation successful."); + return true; +} + +bool glx_initOpenGL_StandardAuto() +{ + bool isContextCreated = glx_initOpenGL_3_2_CoreProfile(); + + if (!isContextCreated) + { + isContextCreated = glx_initOpenGL_LegacyAuto(); + } + + return isContextCreated; +} + +bool glx_initOpenGL_LegacyAuto() +{ + return __glx_initOpenGL(GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 1, 2); +} + +bool glx_initOpenGL_3_2_CoreProfile() +{ + return __glx_initOpenGL(GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 3, 2); +} + +void glx_deinitOpenGL() +{ + if (currDrawable != 0) + { + glXDestroyPbuffer(currDisplay, currDrawable); + currDrawable = 0; + } + + if (pendingDrawable != 0) + { + glXDestroyPbuffer(currDisplay, pendingDrawable); + pendingDrawable = 0; + } + + if ( (currDisplay != NULL) && (currContext != NULL) ) + { + glXMakeContextCurrent(currDisplay, 0, 0, NULL); + glXDestroyContext(currDisplay, currContext); + currContext = NULL; + + __GLXCurrentDisplayClose(); + } + + prevDisplay = NULL; + prevDrawDrawable = 0; + prevReadDrawable = 0; + prevContext = NULL; +} + +bool glx_beginOpenGL() +{ + Bool ret = False; + + prevDisplay = glXGetCurrentDisplay(); + prevDrawDrawable = glXGetCurrentDrawable(); + prevReadDrawable = glXGetCurrentReadDrawable(); + prevContext = glXGetCurrentContext(); + + if (pendingDrawable != NULL) + { + bool previousIsCurrent = (prevDrawDrawable == currDrawable); + + ret = glXMakeContextCurrent(currDisplay, pendingDrawable, pendingDrawable, currContext); + if (ret == True) + { + glXDestroyPbuffer(currDisplay, currDrawable); + currDrawable = pendingDrawable; + + if (previousIsCurrent) + { + prevDrawDrawable = currDrawable; + prevReadDrawable = currDrawable; + } + + pendingDrawable = 0; + } + } + else + { + ret = glXMakeContextCurrent(currDisplay, currDrawable, currDrawable, currContext); + } + + return (ret == True); +} + +void glx_endOpenGL() +{ + if (prevDisplay == NULL) + { + prevDisplay = currDisplay; + } + + if (prevContext == NULL) + { + prevContext = currContext; + } + + if (prevDrawDrawable == 0) + { + prevDrawDrawable = currDrawable; + } + + if (prevReadDrawable == 0) + { + prevReadDrawable = currDrawable; + } + + if ( (prevDisplay != currDisplay) || + (prevContext != currContext) || + (prevDrawDrawable != currDrawable) || + (prevReadDrawable != currDrawable) ) + { + glXMakeContextCurrent(prevDisplay, prevDrawDrawable, prevReadDrawable, prevContext); + } +} + +bool glx_framebufferDidResizeCallback(bool isFBOSupported, size_t w, size_t h) +{ + bool result = false; + + if (isFBOSupported) + { + result = true; + return result; + } + + unsigned int currWidth; + unsigned int currHeight; + glXQueryDrawable(currDisplay, currDrawable, GLX_WIDTH, &currWidth); + glXQueryDrawable(currDisplay, currDrawable, GLX_HEIGHT, &currHeight); + + if ( (w == (size_t)currWidth) && (h == (size_t)currHeight) ) + { + result = true; + return result; + } + + if (pendingDrawable != 0) + { + glXDestroyPbuffer(currDisplay, pendingDrawable); + } + + const int pbufferAttr[] = { + GLX_PBUFFER_WIDTH, (int)w, + GLX_PBUFFER_HEIGHT, (int)h, + 0 + }; + + pendingDrawable = glXCreatePbuffer(currDisplay, bestFBConfig, pbufferAttr); + + result = true; + return result; +} diff --git a/desmume/src/frontend/posix/gtk2/avout.h b/desmume/src/frontend/posix/shared/glx_3Demu.h similarity index 63% rename from desmume/src/frontend/posix/gtk2/avout.h rename to desmume/src/frontend/posix/shared/glx_3Demu.h index 8966856ea..2111dc6b5 100644 --- a/desmume/src/frontend/posix/gtk2/avout.h +++ b/desmume/src/frontend/posix/shared/glx_3Demu.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014 DeSmuME team + Copyright (C) 2024 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,18 +15,16 @@ along with the this software. If not, see . */ -#ifndef _AVOUT_H_ -#define _AVOUT_H_ +#ifndef __GLX_3DEMU_H__ +#define __GLX_3DEMU_H__ -#include "types.h" +bool glx_initOpenGL_StandardAuto(); +bool glx_initOpenGL_LegacyAuto(); +bool glx_initOpenGL_3_2_CoreProfile(); -class AVOut { -public: - virtual bool begin(const char* fname) { return false; } - virtual void end() {} - virtual bool isRecording() { return false; } - virtual void updateAudio(void* soundData, int soundLen) {} - virtual void updateVideo(const u16* buffer) {} -}; +void glx_deinitOpenGL(); +bool glx_beginOpenGL(); +void glx_endOpenGL(); +bool glx_framebufferDidResizeCallback(bool isFBOSupported, size_t w, size_t h); -#endif +#endif // __GLX_3DEMU_H__ diff --git a/desmume/src/frontend/posix/shared/osmesa_3Demu.cpp b/desmume/src/frontend/posix/shared/osmesa_3Demu.cpp new file mode 100644 index 000000000..c3bb790e0 --- /dev/null +++ b/desmume/src/frontend/posix/shared/osmesa_3Demu.cpp @@ -0,0 +1,284 @@ +/* + Copyright (C) 2009 Guillaume Duhamel + Copyright (C) 2009-2024 DeSmuME team + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the this software. If not, see . + */ + +#include +#include + +#include "osmesa_3Demu.h" +#include "OGLRender_3_2.h" + +#warning OSMesa contexts are deprecated. + + +static OSMesaContext currContext = NULL; +static GLint currCtxFormat = GL_UNSIGNED_BYTE; +static GLint currCtxWidth = 0; +static GLint currCtxHeight = 0; +static void *currCtxBuffer = NULL; + +static OSMesaContext prevContext = NULL; +static GLint prevCtxFormat = GL_UNSIGNED_BYTE; +static GLint prevCtxWidth = 0; +static GLint prevCtxHeight = 0; +static void *prevCtxBuffer = NULL; + +static void *pendingCtxBuffer = NULL; +static GLint pendingCtxWidth = 0; +static GLint pendingCtxHeight = 0; + +static bool __osmesa_initOpenGL(const int requestedProfile, const int requestedVersionMajor, const int requestedVersionMinor) +{ + GLboolean ret = GL_FALSE; + + if (currContext != NULL) + { + return true; + } + +#if (((OSMESA_MAJOR_VERSION * 100) + OSMESA_MINOR_VERSION) >= 1102) && defined(OSMESA_CONTEXT_MAJOR_VERSION) + const int ctxAttributes[] = { + OSMESA_FORMAT, OSMESA_RGBA, + OSMESA_DEPTH_BITS, ( (requestedProfile == OSMESA_CORE_PROFILE) && ((requestedVersionMajor >= 4) || ((requestedVersionMajor == 3) && (requestedVersionMinor >= 2))) ) ? 0 : 24, + OSMESA_STENCIL_BITS, ( (requestedProfile == OSMESA_CORE_PROFILE) && ((requestedVersionMajor >= 4) || ((requestedVersionMajor == 3) && (requestedVersionMinor >= 2))) ) ? 0 : 8, + OSMESA_ACCUM_BITS, 0, + OSMESA_PROFILE, requestedProfile, + OSMESA_CONTEXT_MAJOR_VERSION, requestedVersionMajor, + OSMESA_CONTEXT_MINOR_VERSION, requestedVersionMinor, + 0 + }; + + currContext = OSMesaCreateContextAttribs(ctxAttributes, NULL); + if (currContext == NULL) + { + if (requestedProfile == OSMESA_CORE_PROFILE) + { + puts("OSMesa: OSMesaCreateContextAttribs() failed!"); + return false; + } + else if (requestedProfile == OSMESA_COMPAT_PROFILE) + { + puts("OSMesa: Could not create a context using OSMesaCreateContextAttribs(). Will attempt to use OSMesaCreateContextExt() instead..."); + } + } + + if ( (currContext == NULL) && (requestedProfile == OSMESA_COMPAT_PROFILE) ) +#endif + { + currContext = OSMesaCreateContextExt(OSMESA_RGBA, 24, 8, 0, NULL); + if (currContext == NULL) + { + puts("OSMesa: OSMesaCreateContextExt() failed!"); + return false; + } + } + + currCtxFormat = GL_UNSIGNED_BYTE; + currCtxWidth = GPU_FRAMEBUFFER_NATIVE_WIDTH; + currCtxHeight = GPU_FRAMEBUFFER_NATIVE_HEIGHT; + + currCtxBuffer = malloc_alignedPage(currCtxWidth * currCtxHeight * sizeof(uint32_t)); + if (currCtxBuffer == NULL) + { + OSMesaDestroyContext(currContext); + currCtxFormat = GL_UNSIGNED_BYTE; + currCtxWidth = 0; + currCtxHeight = 0; + + puts("OSMesa: Could not allocate enough memory for the context!"); + return false; + } + + puts("OSMesa: Context creation successful."); + return true; +} + +bool osmesa_initOpenGL_StandardAuto() +{ + bool isContextCreated = __osmesa_initOpenGL(OSMESA_CORE_PROFILE, 4, 1); + + if (!isContextCreated) + { + isContextCreated = osmesa_initOpenGL_3_2_CoreProfile(); + } + + if (!isContextCreated) + { + isContextCreated = osmesa_initOpenGL_LegacyAuto(); + } + + return isContextCreated; +} + +bool osmesa_initOpenGL_LegacyAuto() +{ + return __osmesa_initOpenGL(OSMESA_COMPAT_PROFILE, 1, 2); +} + +bool osmesa_initOpenGL_3_2_CoreProfile() +{ + return __osmesa_initOpenGL(OSMESA_CORE_PROFILE, 3, 2); +} + +void osmesa_deinitOpenGL() +{ + OSMesaMakeCurrent(NULL, NULL, GL_UNSIGNED_BYTE, 0, 0); + + if (currContext != NULL) + { + OSMesaDestroyContext(currContext); + currContext = NULL; + currCtxFormat = GL_UNSIGNED_BYTE; + } + + if (currCtxBuffer != NULL) + { + free_aligned(currCtxBuffer); + currCtxBuffer = NULL; + currCtxWidth = 0; + currCtxHeight = 0; + } + + if (pendingCtxBuffer != NULL) + { + free_aligned(pendingCtxBuffer); + pendingCtxBuffer = NULL; + pendingCtxWidth = 0; + pendingCtxHeight = 0; + } + + prevContext = NULL; + prevCtxFormat = GL_UNSIGNED_BYTE; + prevCtxWidth = 0; + prevCtxHeight = 0; + prevCtxBuffer = NULL; +} + +bool osmesa_beginOpenGL() +{ + GLboolean ret = GL_FALSE; + OSMesaContext oldContext = OSMesaGetCurrentContext(); + + if (oldContext != NULL) + { + prevContext = oldContext; + OSMesaGetColorBuffer(prevContext, &prevCtxWidth, &prevCtxHeight, &prevCtxFormat, &prevCtxBuffer); + } + else + { + prevContext = currContext; + prevCtxFormat = currCtxFormat; + prevCtxWidth = currCtxWidth; + prevCtxHeight = currCtxHeight; + prevCtxBuffer = currCtxBuffer; + } + + if (pendingCtxBuffer != NULL) + { + bool previousIsCurrent = (prevCtxBuffer == currCtxBuffer); + + ret = OSMesaMakeCurrent(currContext, pendingCtxBuffer, currCtxFormat, pendingCtxWidth, pendingCtxHeight);; + if (ret == GL_TRUE) + { + free_aligned(currCtxBuffer); + currCtxBuffer = pendingCtxBuffer; + + if (previousIsCurrent) + { + prevCtxBuffer = pendingCtxBuffer; + prevCtxWidth = pendingCtxWidth; + prevCtxHeight = pendingCtxHeight; + } + + pendingCtxBuffer = NULL; + pendingCtxWidth = 0; + pendingCtxHeight = 0; + } + } + else + { + ret = OSMesaMakeCurrent(currContext, currCtxBuffer, currCtxFormat, currCtxWidth, currCtxHeight); + } + + return (ret == GL_TRUE); +} + +void osmesa_endOpenGL() +{ + if (prevContext == NULL) + { + prevContext = currContext; + } + + if (prevCtxBuffer == NULL) + { + prevCtxBuffer = currCtxBuffer; + } + + if (prevCtxWidth == 0) + { + prevCtxWidth = currCtxWidth; + } + + if (prevCtxHeight == 0) + { + prevCtxHeight = currCtxHeight; + } + + if (prevCtxFormat == GL_UNSIGNED_BYTE) + { + prevCtxFormat = currCtxFormat; + } + + if ( (prevContext != currContext) || + (prevCtxBuffer != currCtxBuffer) || + (prevCtxFormat != currCtxFormat) || + (prevCtxWidth != currCtxWidth) || + (prevCtxHeight != currCtxHeight) ) + { + OSMesaMakeCurrent(prevContext, prevCtxBuffer, prevCtxFormat, prevCtxWidth, prevCtxHeight); + } +} + +bool osmesa_framebufferDidResizeCallback(bool isFBOSupported, size_t w, size_t h) +{ + bool result = false; + + if (isFBOSupported) + { + result = true; + return result; + } + + if ( (w == (size_t)currCtxWidth) && (h == (size_t)currCtxHeight) ) + { + result = true; + return result; + } + + if (pendingCtxBuffer != NULL) + { + free_aligned(pendingCtxBuffer); + } + + pendingCtxWidth = (GLint)w; + pendingCtxHeight = (GLint)h; + pendingCtxBuffer = malloc_alignedPage(w * h * sizeof(uint32_t)); + + result = true; + return result; +} diff --git a/desmume/src/frontend/posix/gtk2/osmesa_3Demu.h b/desmume/src/frontend/posix/shared/osmesa_3Demu.h similarity index 68% rename from desmume/src/frontend/posix/gtk2/osmesa_3Demu.h rename to desmume/src/frontend/posix/shared/osmesa_3Demu.h index af6a9f4db..df452160e 100644 --- a/desmume/src/frontend/posix/gtk2/osmesa_3Demu.h +++ b/desmume/src/frontend/posix/shared/osmesa_3Demu.h @@ -1,27 +1,32 @@ /* Copyright (C) 2009 Guillaume Duhamel - Copyright (C) 2009-2017 DeSmuME team - + Copyright (C) 2009-2024 DeSmuME team + This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with the this software. If not, see . */ #ifndef OSMESA_3DEMU_H -#define OSMESA_3DEMU_H - -bool init_osmesa_3Demu(void); -void deinit_osmesa_3Demu(void); -bool is_osmesa_initialized(void); +#define OSMESA_3DEMU_H + +bool osmesa_initOpenGL_StandardAuto(); +bool osmesa_initOpenGL_LegacyAuto(); +bool osmesa_initOpenGL_3_2_CoreProfile(); + +void osmesa_deinitOpenGL(); +bool osmesa_beginOpenGL(); +void osmesa_endOpenGL(); +bool osmesa_framebufferDidResizeCallback(bool isFBOSupported, size_t w, size_t h); #endif // OSMESA_3DEMU_H diff --git a/desmume/src/frontend/posix/shared/sdl_3Demu.cpp b/desmume/src/frontend/posix/shared/sdl_3Demu.cpp new file mode 100644 index 000000000..98f5e9a1d --- /dev/null +++ b/desmume/src/frontend/posix/shared/sdl_3Demu.cpp @@ -0,0 +1,232 @@ +/* + Copyright (C) 2020 Emmanuel Gil Peyrot + Copyright (C) 2020-2024 DeSmuME team + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the this software. If not, see . + */ + +#include +#include + +#include "sdl_3Demu.h" + + +static SDL_Window *currWindow = NULL; +static SDL_GLContext currContext = NULL; + +static SDL_Window *prevWindow = NULL; +static SDL_GLContext prevContext = NULL; + +static SDL_Window *pendingWindow = NULL; + +static bool __sdl_initOpenGL(const int requestedProfile, const int requestedVersionMajor, const int requestedVersionMinor) +{ + bool result = false; + char ctxString[32] = {0}; + + if (requestedProfile == SDL_GL_CONTEXT_PROFILE_CORE) + { + snprintf(ctxString, sizeof(ctxString), "SDL (Core %i.%i)", requestedVersionMajor, requestedVersionMinor); + } + else if (requestedProfile == SDL_GL_CONTEXT_PROFILE_COMPATIBILITY) + { + snprintf(ctxString, sizeof(ctxString), "SDL (Compatibility %i.%i)", requestedVersionMajor, requestedVersionMinor); + } + else if (requestedProfile == SDL_GL_CONTEXT_PROFILE_ES) + { + snprintf(ctxString, sizeof(ctxString), "SDL (ES %i.%i)", requestedVersionMajor, requestedVersionMinor); + } + else + { + puts("SDL: Invalid profile submitted. No context will be created."); + return result; + } + + if (currContext != NULL) + { + result = true; + return result; + } + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, ((requestedProfile == SDL_GL_CONTEXT_PROFILE_CORE) || (requestedProfile == SDL_GL_CONTEXT_PROFILE_ES)) ? 0 : 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, ((requestedProfile == SDL_GL_CONTEXT_PROFILE_CORE) || (requestedProfile == SDL_GL_CONTEXT_PROFILE_ES)) ? 0 : 8); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, requestedProfile); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, requestedVersionMajor); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, requestedVersionMinor); + + currWindow = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 256, 192, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN); + if (currWindow == NULL) + { + fprintf(stderr, "%s: Failed to create a window: %s\n", ctxString, SDL_GetError()); + return false; + } + + currContext = SDL_GL_CreateContext(currWindow); + if (currContext == NULL) + { + SDL_DestroyWindow(currWindow); + currWindow = NULL; + + fprintf(stderr, "%s: Failed to create an OpenGL context: %s\n", ctxString, SDL_GetError()); + return false; + } + + printf("%s: OpenGL context creation successful.\n", ctxString); + return true; +} + +bool sdl_initOpenGL_StandardAuto() +{ + bool isContextCreated = sdl_initOpenGL_3_2_CoreProfile(); + + if (!isContextCreated) + { + isContextCreated = sdl_initOpenGL_LegacyAuto(); + } + + return isContextCreated; +} + +bool sdl_initOpenGL_LegacyAuto() +{ + return __sdl_initOpenGL(SDL_GL_CONTEXT_PROFILE_COMPATIBILITY, 1, 2); +} + +bool sdl_initOpenGL_3_2_CoreProfile() +{ + return __sdl_initOpenGL(SDL_GL_CONTEXT_PROFILE_CORE, 3, 2); +} + +bool sdl_initOpenGL_ES_3_0() +{ + return __sdl_initOpenGL(SDL_GL_CONTEXT_PROFILE_ES, 3, 0); +} + +void sdl_deinitOpenGL() +{ + SDL_GL_MakeCurrent(NULL, NULL); + + if (currContext != NULL) + { + SDL_GL_DeleteContext(currContext); + currContext = NULL; + } + + if (currWindow != NULL) + { + SDL_DestroyWindow(currWindow); + currWindow = NULL; + } + + if (pendingWindow != NULL) + { + SDL_DestroyWindow(pendingWindow); + pendingWindow = NULL; + } + + prevWindow = NULL; + prevContext = NULL; +} + +bool sdl_beginOpenGL() +{ + int ret = 1; + + prevWindow = SDL_GL_GetCurrentWindow(); + prevContext = SDL_GL_GetCurrentContext(); + + if (pendingWindow != NULL) + { + bool previousIsCurrent = (prevWindow == currWindow); + + ret = SDL_GL_MakeCurrent(pendingWindow, currContext); + if (ret == 0) + { + SDL_DestroyWindow(currWindow); + currWindow = pendingWindow; + + if (previousIsCurrent) + { + prevWindow = currWindow; + } + + pendingWindow = NULL; + } + } + else + { + ret = SDL_GL_MakeCurrent(currWindow, currContext); + } + + return (ret == 0); +} + +void sdl_endOpenGL() +{ + if (prevWindow == NULL) + { + prevWindow = currWindow; + } + + if (prevContext == NULL) + { + prevContext = currContext; + } + + if ( (prevWindow != currWindow) || + (prevContext != currContext) ) + { + SDL_GL_MakeCurrent(prevWindow, prevContext); + } +} + +bool sdl_framebufferDidResizeCallback(bool isFBOSupported, size_t w, size_t h) +{ + bool result = false; + + if (isFBOSupported) + { + result = true; + return result; + } + + int currWidth; + int currHeight; + SDL_GetWindowSize(currWindow, &currWidth, &currHeight); + + if ( (w == (size_t)currWidth) && (h == (size_t)currHeight) ) + { + result = true; + return result; + } + + if (pendingWindow != NULL) + { + SDL_DestroyWindow(pendingWindow); + } + + pendingWindow = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, (int)w, (int)h, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN); + if (currWindow == NULL) + { + fprintf(stderr, "SDL: sdl_framebufferDidResizeCallback failed to create the resized window: %s\n", SDL_GetError()); + return result; + } + + result = true; + return result; +} diff --git a/desmume/src/frontend/posix/gtk2/sdl_3Demu.h b/desmume/src/frontend/posix/shared/sdl_3Demu.h similarity index 68% rename from desmume/src/frontend/posix/gtk2/sdl_3Demu.h rename to desmume/src/frontend/posix/shared/sdl_3Demu.h index 2088263da..2e9b5fe2d 100644 --- a/desmume/src/frontend/posix/gtk2/sdl_3Demu.h +++ b/desmume/src/frontend/posix/shared/sdl_3Demu.h @@ -1,16 +1,17 @@ /* Copyright (C) 2020 Emmanuel Gil Peyrot - + Copyright (C) 2020-2024 DeSmuME team + This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. - + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with the this software. If not, see . */ @@ -18,9 +19,15 @@ #ifndef SDL_3DEMU_H #define SDL_3DEMU_H -bool init_sdl_3Demu(void); -bool deinit_sdl_3Demu(void); -bool is_sdl_initialized(void); +bool sdl_initOpenGL_StandardAuto(); +bool sdl_initOpenGL_LegacyAuto(); +bool sdl_initOpenGL_3_2_CoreProfile(); +bool sdl_initOpenGL_ES_3_0(); + +void sdl_deinitOpenGL(); +bool sdl_beginOpenGL(); +void sdl_endOpenGL(); +bool sdl_framebufferDidResizeCallback(bool isFBOSupported, size_t w, size_t h); #endif // SDL_3DEMU_H