diff --git a/Makefile b/Makefile index e31cece033..fbb47c0a80 100644 --- a/Makefile +++ b/Makefile @@ -249,6 +249,12 @@ ifeq ($(HAVE_OPENGL), 1) OBJ += gfx/context/mali_fbdev_ctx.o endif + ifeq ($(HAVE_VIVANTE_FBDEV), 1) + OBJ += gfx/context/vivante_fbdev_ctx.o + DEFINES += $(EGL_CFLAGS) + LIBS += $(EGL_LIBS) + endif + ifeq ($(HAVE_X11), 1) ifeq ($(HAVE_GLES), 0) OBJ += gfx/context/glx_ctx.o diff --git a/gfx/context/vivante_fbdev_ctx.c b/gfx/context/vivante_fbdev_ctx.c new file mode 100644 index 0000000000..a3dc2df72a --- /dev/null +++ b/gfx/context/vivante_fbdev_ctx.c @@ -0,0 +1,285 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#include "../../driver.h" +#include "../../general.h" +#include "../gfx_common.h" +#include "../gl_common.h" + +#include +#include + +static EGLContext g_egl_ctx; +static EGLSurface g_egl_surf; +static EGLDisplay g_egl_dpy; +static EGLConfig g_config; +static bool g_resize; +static unsigned g_width, g_height; + +static volatile sig_atomic_t g_quit; +static void sighandler(int sig) +{ + (void)sig; + g_quit = 1; +} + +static void gfx_ctx_set_swap_interval(void *data, unsigned interval) +{ + (void)data; + if (g_egl_dpy) + eglSwapInterval(g_egl_dpy, interval); +} + +static void gfx_ctx_destroy(void *data) +{ + (void)data; + + if (g_egl_dpy != EGL_NO_DISPLAY) + { + if (g_egl_ctx != EGL_NO_CONTEXT) + { + glFlush(); + glFinish(); + } + + eglMakeCurrent(g_egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (g_egl_ctx != EGL_NO_CONTEXT) + eglDestroyContext(g_egl_dpy, g_egl_ctx); + if (g_egl_surf != EGL_NO_SURFACE) + eglDestroySurface(g_egl_dpy, g_egl_surf); + eglTerminate(g_egl_dpy); + } + + g_egl_dpy = EGL_NO_DISPLAY; + g_egl_surf = EGL_NO_SURFACE; + g_egl_ctx = EGL_NO_CONTEXT; + g_config = 0; + g_quit = 0; + g_resize = false; +} + +static void gfx_ctx_get_video_size(void *data, unsigned *width, unsigned *height) +{ + (void)data; + if (g_egl_dpy != EGL_NO_DISPLAY && g_egl_surf != EGL_NO_SURFACE) + { + EGLint gl_width, gl_height; + eglQuerySurface(g_egl_dpy, g_egl_surf, EGL_WIDTH, &gl_width); + eglQuerySurface(g_egl_dpy, g_egl_surf, EGL_HEIGHT, &gl_height); + *width = gl_width; + *height = gl_height; + } + else + { + *width = 0; + *height = 0; + } +} + +static bool gfx_ctx_init(void *data) +{ + (void)data; + + struct sigaction sa = {{0}}; + sa.sa_handler = sighandler; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + static const EGLint attribs[] = { + //EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + //EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_BLUE_SIZE, 5, + EGL_GREEN_SIZE, 6, + EGL_RED_SIZE, 5, + EGL_ALPHA_SIZE, 0, + EGL_SAMPLES, 0, + EGL_NONE + }; + EGLint num_config; + EGLint egl_version_major, egl_version_minor; + EGLint format; + + RARCH_LOG("[Vivante fbdev]: Initializing context\n"); + + if ((g_egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY) + { + RARCH_ERR("[Vivante fbdev]: eglGetDisplay failed.\n"); + goto error; + } + + if (!eglInitialize(g_egl_dpy, &egl_version_major, &egl_version_minor)) + { + RARCH_ERR("[Vivante fbdev]: eglInitialize failed.\n"); + goto error; + } + + RARCH_LOG("[Vivante fbdev]: EGL version: %d.%d\n", egl_version_major, egl_version_minor); + + + if (!eglChooseConfig(g_egl_dpy, attribs, &g_config, 1, &num_config)) + { + RARCH_ERR("[Vivante fbdev]: eglChooseConfig failed.\n"); + goto error; + } + + return true; + +error: + RARCH_ERR("[Vivante fbdev]: EGL error: %d.\n", eglGetError()); + gfx_ctx_destroy(data); + return false; +} + +static void gfx_ctx_swap_buffers(void *data) +{ + (void)data; + eglSwapBuffers(g_egl_dpy, g_egl_surf); +} + +static void gfx_ctx_check_window(void *data, bool *quit, + bool *resize, unsigned *width, unsigned *height, unsigned frame_count) +{ + (void)frame_count; + + unsigned new_width, new_height; + gfx_ctx_get_video_size(data, &new_width, &new_height); + if (new_width != *width || new_height != *height) + { + *width = new_width; + *height = new_height; + *resize = true; + } + + *quit = g_quit; +} + +static void gfx_ctx_set_resize(void *data, unsigned width, unsigned height) +{ + (void)data; + (void)width; + (void)height; +} + +static void gfx_ctx_update_window_title(void *data) +{ + (void)data; + char buf[128], buf_fps[128]; + bool fps_draw = g_settings.fps_show; + gfx_get_fps(buf, sizeof(buf), fps_draw ? buf_fps : NULL, sizeof(buf_fps)); + + if (fps_draw) + msg_queue_push(g_extern.msg_queue, buf_fps, 1, 1); +} + +static bool gfx_ctx_set_video_mode(void *data, + unsigned width, unsigned height, + bool fullscreen) +{ + // Pick some arbitrary default. + if (!width || !fullscreen) + width = 1280; + if (!height || !fullscreen) + height = 1024; + + g_width = width; + g_height = height; + + static const EGLint attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, // Use version 2, even for GLES3. + EGL_NONE + }; + + EGLNativeWindowType window = fbCreateWindow(fbGetDisplayByIndex(0), 0, 0, 0, 0); + if ((g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_config, window, 0)) == EGL_NO_SURFACE) + { + RARCH_ERR("eglCreateWindowSurface failed.\n"); + goto error; + } + + if ((g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, 0, attribs)) == EGL_NO_CONTEXT) + { + RARCH_ERR("eglCreateContext failed.\n"); + goto error; + } + + if (!eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx)) + { + RARCH_ERR("eglMakeCurrent failed.\n"); + goto error; + } + + return true; + +error: + RARCH_ERR("[Vivante fbdev]: EGL error: %d.\n", eglGetError()); + gfx_ctx_destroy(data); + return false; +} + +static void gfx_ctx_input_driver(void *data, const input_driver_t **input, void **input_data) +{ + (void)data; + *input = NULL; + *input_data = NULL; +} + +static gfx_ctx_proc_t gfx_ctx_get_proc_address(const char *symbol) +{ + rarch_assert(sizeof(void*) == sizeof(void (*)(void))); + gfx_ctx_proc_t ret; + + void *sym__ = eglGetProcAddress(symbol); + memcpy(&ret, &sym__, sizeof(void*)); + + return ret; +} + +static bool gfx_ctx_bind_api(void *data, enum gfx_ctx_api api, unsigned major, unsigned minor) +{ + (void)data; + return api == GFX_CTX_OPENGL_ES_API; +} + +static bool gfx_ctx_has_focus(void *data) +{ + (void)data; + return true; +} + +const gfx_ctx_driver_t gfx_ctx_vivante_fbdev = { + gfx_ctx_init, + gfx_ctx_destroy, + gfx_ctx_bind_api, + gfx_ctx_set_swap_interval, + gfx_ctx_set_video_mode, + gfx_ctx_get_video_size, + NULL, + gfx_ctx_update_window_title, + gfx_ctx_check_window, + gfx_ctx_set_resize, + gfx_ctx_has_focus, + gfx_ctx_swap_buffers, + gfx_ctx_input_driver, + gfx_ctx_get_proc_address, +#ifdef HAVE_EGL + NULL, + NULL, +#endif + NULL, + "vivante-fbdev", +}; + diff --git a/gfx/gfx_context.c b/gfx/gfx_context.c index 5c586c6ea2..bd26c30c1c 100644 --- a/gfx/gfx_context.c +++ b/gfx/gfx_context.c @@ -35,6 +35,9 @@ static const gfx_ctx_driver_t *gfx_ctx_drivers[] = { #if defined(HAVE_MALI_FBDEV) &gfx_ctx_mali_fbdev, #endif +#if defined(HAVE_VIVANTE_FBDEV) + &gfx_ctx_vivante_fbdev, +#endif #if defined(_WIN32) && defined(HAVE_OPENGL) &gfx_ctx_wgl, #endif diff --git a/gfx/gfx_context.h b/gfx/gfx_context.h index 7005bb830b..dae9495ad1 100644 --- a/gfx/gfx_context.h +++ b/gfx/gfx_context.h @@ -114,6 +114,7 @@ extern const gfx_ctx_driver_t gfx_ctx_glx; extern const gfx_ctx_driver_t gfx_ctx_d3d9; extern const gfx_ctx_driver_t gfx_ctx_drm_egl; extern const gfx_ctx_driver_t gfx_ctx_mali_fbdev; +extern const gfx_ctx_driver_t gfx_ctx_vivante_fbdev; extern const gfx_ctx_driver_t gfx_ctx_android; extern const gfx_ctx_driver_t gfx_ctx_ps3; extern const gfx_ctx_driver_t gfx_ctx_wgl; diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 6aebe019eb..8d480e58d7 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -276,6 +276,6 @@ add_define_make OS "$OS" # Creates config.mk and config.h. add_define_make GLOBAL_CONFIG_DIR "$GLOBAL_CONFIG_DIR" -VARS="RGUI LAKKA ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL OPENGL OMAP GLES GLES3 VG EGL KMS EXYNOS GBM DRM DYLIB GETOPT_LONG THREADS CG LIBXML2 ZLIB DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL SWSCALE FREETYPE XKBCOMMON XVIDEO X11 XEXT XF86VM XINERAMA MALI_FBDEV NETPLAY NETWORK_CMD STDIN_CMD COMMAND SOCKET_LEGACY FBO STRL STRCASESTR MMAP PYTHON FFMPEG_ALLOC_CONTEXT3 FFMPEG_AVCODEC_OPEN2 FFMPEG_AVIO_OPEN FFMPEG_AVFORMAT_WRITE_HEADER FFMPEG_AVFORMAT_NEW_STREAM FFMPEG_AVCODEC_ENCODE_AUDIO2 FFMPEG_AVCODEC_ENCODE_VIDEO2 BSV_MOVIE VIDEOCORE NEON FLOATHARD FLOATSOFTFP UDEV V4L2 AV_CHANNEL_LAYOUT" +VARS="RGUI LAKKA ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL OPENGL OMAP GLES GLES3 VG EGL KMS EXYNOS GBM DRM DYLIB GETOPT_LONG THREADS CG LIBXML2 ZLIB DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL SWSCALE FREETYPE XKBCOMMON XVIDEO X11 XEXT XF86VM XINERAMA MALI_FBDEV VIVANTE_FBDEV NETPLAY NETWORK_CMD STDIN_CMD COMMAND SOCKET_LEGACY FBO STRL STRCASESTR MMAP PYTHON FFMPEG_ALLOC_CONTEXT3 FFMPEG_AVCODEC_OPEN2 FFMPEG_AVIO_OPEN FFMPEG_AVFORMAT_WRITE_HEADER FFMPEG_AVFORMAT_NEW_STREAM FFMPEG_AVCODEC_ENCODE_AUDIO2 FFMPEG_AVCODEC_ENCODE_VIDEO2 BSV_MOVIE VIDEOCORE NEON FLOATHARD FLOATSOFTFP UDEV V4L2 AV_CHANNEL_LAYOUT" create_config_make config.mk $VARS create_config_header config.h $VARS diff --git a/qb/config.params.sh b/qb/config.params.sh index bc9af0e459..06000ee69b 100644 --- a/qb/config.params.sh +++ b/qb/config.params.sh @@ -14,6 +14,7 @@ HAVE_NETPLAY=auto # Enable netplay support HAVE_OPENGL=yes # Disable OpenGL support HAVE_GLES=no # Use GLESv2 instead of desktop GL HAVE_MALI_FBDEV=no # Enable Mali fbdev context support +HAVE_VIVANTE_FBDEV=no # Enable Vivante fbdev context support HAVE_GLES3=no # Enable OpenGLES3 support HAVE_X11=auto # Disable everything X11. HAVE_OMAP=no # Enable OMAP video support