From 350af0a4581cbbe20be2ebe8b15dceec2dd37c29 Mon Sep 17 00:00:00 2001 From: Toad King Date: Wed, 23 May 2012 02:31:29 -0400 Subject: [PATCH 01/21] initial Raspberry Pi work. Currently just displays a solid blue screen. --- Makefile | 7 +- config.def.h | 5 +- driver.c | 3 + driver.h | 1 + gfx/rpi.c | 439 ++++++++++++++++++++++++++++++++++++++++++++++ qb/config.libs.sh | 12 +- retroarch.c | 7 + settings.c | 2 + 8 files changed, 473 insertions(+), 3 deletions(-) create mode 100644 gfx/rpi.c diff --git a/Makefile b/Makefile index 4ca552f44b..893bda1415 100644 --- a/Makefile +++ b/Makefile @@ -114,6 +114,11 @@ endif endif endif +ifeq ($(HAVE_RPI), 1) + OBJ += gfx/rpi.o + LIBS += -lGLESv2 -lEGL -lbcm_host +endif + ifeq ($(HAVE_XVIDEO), 1) OBJ += gfx/xvideo.o input/x11_input.o LIBS += $(XVIDEO_LIBS) $(X11_LIBS) $(XEXT_LIBS) @@ -190,7 +195,7 @@ ifeq ($(DEBUG), 1) OPTIMIZE_FLAG = -O0 endif -CFLAGS += -Wall $(OPTIMIZE_FLAG) -g -I. -pedantic +CFLAGS += -Wall $(OPTIMIZE_FLAG) $(INCLUDE_DIRS) -g -I. -pedantic ifeq ($(CXX_BUILD), 1) CFLAGS += -std=c++0x -xc++ -D__STDC_CONSTANT_MACROS else diff --git a/config.def.h b/config.def.h index b2178a6172..749ca8f178 100644 --- a/config.def.h +++ b/config.def.h @@ -38,6 +38,7 @@ #define VIDEO_WII 24 #define VIDEO_XENON360 25 #define VIDEO_XDK360 28 +#define VIDEO_RPI 29 //////////////////////// #define AUDIO_RSOUND 1 #define AUDIO_OSS 2 @@ -64,7 +65,9 @@ #define INPUT_XDK360 26 //////////////////////// -#if defined(HAVE_OPENGL) || defined(__CELLOS_LV2__) +#if defined(HAVE_RPI) +#define VIDEO_DEFAULT_DRIVER VIDEO_RPI +#elif defined(HAVE_OPENGL) || defined(__CELLOS_LV2__) #define VIDEO_DEFAULT_DRIVER VIDEO_GL #elif defined(GEKKO) #define VIDEO_DEFAULT_DRIVER VIDEO_WII diff --git a/driver.c b/driver.c index 7f7fb83069..5d957c982b 100644 --- a/driver.c +++ b/driver.c @@ -99,6 +99,9 @@ static const video_driver_t *video_drivers[] = { #ifdef GEKKO &video_wii, #endif +#ifdef HAVE_RPI + &video_rpi, +#endif }; static const input_driver_t *input_drivers[] = { diff --git a/driver.h b/driver.h index 0666597ba0..5dd541f988 100644 --- a/driver.h +++ b/driver.h @@ -203,6 +203,7 @@ extern const video_driver_t video_xenon360; extern const video_driver_t video_xvideo; extern const video_driver_t video_xdk360; extern const video_driver_t video_sdl; +extern const video_driver_t video_rpi; extern const video_driver_t video_ext; extern const input_driver_t input_sdl; extern const input_driver_t input_x; diff --git a/gfx/rpi.c b/gfx/rpi.c new file mode 100644 index 0000000000..f364260dfb --- /dev/null +++ b/gfx/rpi.c @@ -0,0 +1,439 @@ +#include +#include +#include +#include +#include +#include +#include +#include "../libretro.h" +#include "../general.h" + +static inline unsigned get_alignment(unsigned pitch) +{ + if (pitch & 1) + return 1; + if (pitch & 2) + return 2; + if (pitch & 4) + return 4; + return 8; +} + +static const GLfloat default_vertices[] = { + 0, 0, + 0, 1, + 1, 1, + 1, 0 +}; + +typedef struct rpi { + EGLDisplay mDisplay; + EGLSurface mSurface; + EGLContext mContext; + uint32_t mScreenWidth; + uint32_t mScreenHeight; + GLint mTextureWidth; + GLint mTextureHeight; + unsigned mRenderWidth; + unsigned mRenderHeight; + int mBpp; + GLenum mTexType; + GLuint mTexture; + GLuint mPalette; + GLuint mVertBuf; + GLuint vshader; + GLuint fshader; + GLuint program; + GLfloat mTexVertices[8]; + uint8_t *mEmptyBuf; +} rpi_t; + +static uint16_t rgba1555_to_rgba5551[0x10000]; + +static void rpi_setup_palette(rpi_t *rpi) +{ + // because GLES doesn't have GL_UNSIGNED_SHORT_1_5_5_5_REV, we fake it with this shader + static const GLchar *vertex_shader_src = + "attribute vec4 vertex;\n" + "varying vec2 tcoord;\n" + "void main(void)\n" + "{\n" + "vec4 pos = vertex;\n" + "gl_Position = vertex;\n" + "tcoord = vertex.xy; // * 0.5 + 0.5;\n" + "}"; + + static const GLchar *fragment_shader_16_src = + "uniform sampler2D pal;\n" + "uniform sampler2D tex;\n" + "varying vec2 tcoord;\n" + "void main()\n" + "{\n" + "const float scale = 255.0 / 256.0;\n" + "const float offset = 0.5 / 255.0 * scale;\n" + "vec4 color = texture2D(tex, tcoord.xy);\n" + "float r = color.r / 32.0;\n" + "float g = color.g;\n" + "float b = color.b / 32.0;\n" + "float a = color.a;\n" + "float pixelx = (a + r) * scale + offset;\n" + "float pixely = (g + b) * scale + offset;\n" + "vec2 coords = vec2(pixelx, pixely);\n" + "gl_FragColor = texture2D(pal, coords);\n" + "}"; + + static const GLchar *fragment_shader_32_src = + "uniform sampler2D pal;\n" + "uniform sampler2D tex;\n" + "varying vec2 tcoord;\n" + "void main()\n" + "{\n" + "vec4 color = texture2D(tex, tcoord.xy);\n" + "gl_FragColor = vec4(color.b, color.g, color.r, color.a);\n" + "}"; + + GLint compiled, linked; + GLuint unif_pal, unif_tex; + int i, a, r, g, b; + + for(i = 0; i < 0x10000; i++) + { + a = (i & 0x8000) >> 15; + r = (i & 0x7C00) >> 9; + g = (i & 0x03E0) << 1; + b = (i & 0x001F) << 11; + rgba1555_to_rgba5551[i] = a | r | g | b; + } + + glActiveTexture(GL_TEXTURE1); + glGenTextures(1, &rpi->mPalette); + glBindTexture(GL_TEXTURE_2D, rpi->mPalette); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, rgba1555_to_rgba5551); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + rpi->vshader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(rpi->vshader, 1, &vertex_shader_src, 0); + glCompileShader(rpi->vshader); + + glGetShaderiv ( rpi->vshader, GL_COMPILE_STATUS, &compiled ); + + if ( !compiled ) + { + GLint infoLen = 0; + glGetShaderiv ( rpi->vshader, GL_INFO_LOG_LENGTH, &infoLen ); + + if ( infoLen > 1 ) + { + char* infoLog = malloc (sizeof(char) * infoLen ); + glGetShaderInfoLog ( rpi->vshader, infoLen, NULL, infoLog ); + printf ( "Error compiling shader:\n%s\n", infoLog ); + free ( infoLog ); + } + + glDeleteShader ( rpi->vshader ); + exit(1); + } + + rpi->fshader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(rpi->fshader, 1, rpi->mBpp == 2 ? &fragment_shader_16_src : &fragment_shader_32_src, 0); + glCompileShader(rpi->fshader); + + glGetShaderiv ( rpi->fshader, GL_COMPILE_STATUS, &compiled ); + + if ( !compiled ) + { + GLint infoLen = 0; + glGetShaderiv ( rpi->fshader, GL_INFO_LOG_LENGTH, &infoLen ); + + if ( infoLen > 1 ) + { + char* infoLog = malloc (sizeof(char) * infoLen ); + glGetShaderInfoLog ( rpi->fshader, infoLen, NULL, infoLog ); + printf ( "Error compiling shader:\n%s\n", infoLog ); + free ( infoLog ); + } + + glDeleteShader ( rpi->fshader ); + exit(1); + } + + rpi->program = glCreateProgram(); + glAttachShader(rpi->program, rpi->vshader); + glAttachShader(rpi->program, rpi->fshader); + glBindAttribLocation(rpi->program, 0, "vertex"); + glLinkProgram(rpi->program); + + glGetProgramiv ( rpi->program, GL_LINK_STATUS, &linked ); + if ( !linked ) + { + GLint infoLen = 0; + glGetProgramiv ( rpi->program, GL_INFO_LOG_LENGTH, &infoLen ); + + if ( infoLen > 1 ) + { + char* infoLog = malloc (sizeof(char) * infoLen ); + glGetProgramInfoLog ( rpi->program, infoLen, NULL, infoLog ); + printf( "Error linking program:\n%s\n", infoLog ); + free ( infoLog ); + } + + glDeleteProgram ( rpi->program ); + exit(1); + } + +// unif_pal = glGetUniformLocation(rpi->program, "pal"); +// unif_tex = glGetUniformLocation(rpi->program, "tex"); + +// glUniform1i(unif_pal, 1); +// glUniform1i(unif_tex, 0); + + // reset to screen texture + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, rpi->mTexture); + assert(glGetError() == 0); +} + +static void rpi_set_nonblock_state(void *data, bool state) +{ + rpi_t *rpi = (rpi_t*)data; + eglSwapInterval(rpi->mDisplay, state ? 1 : 0); +} + +static void *rpi_init(const video_info_t *video, const input_driver_t **input, void **input_data) +{ + int32_t success; + EGLBoolean result; + EGLint num_config; + rpi_t *rpi = (rpi_t*)calloc(1, sizeof(rpi_t)); + *input = NULL; + + static EGL_DISPMANX_WINDOW_T nativewindow; + + DISPMANX_ELEMENT_HANDLE_T dispman_element; + DISPMANX_DISPLAY_HANDLE_T dispman_display; + DISPMANX_UPDATE_HANDLE_T dispman_update; + DISPMANX_MODEINFO_T dispman_modeinfo; + VC_RECT_T dst_rect; + VC_RECT_T src_rect; + + static const EGLint attribute_list[] = + { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_NONE + }; + + EGLConfig config; + + // get an EGL display connection + rpi->mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + assert(rpi->mDisplay != EGL_NO_DISPLAY); + + // initialize the EGL display connection + result = eglInitialize(rpi->mDisplay, NULL, NULL); + assert(result != EGL_FALSE); + + // get an appropriate EGL frame buffer configuration + result = eglChooseConfig(rpi->mDisplay, attribute_list, &config, 1, &num_config); + assert(result != EGL_FALSE); + + // create an EGL rendering context + rpi->mContext = eglCreateContext(rpi->mDisplay, config, EGL_NO_CONTEXT, NULL); + assert(rpi->mContext != EGL_NO_CONTEXT); + + // create an EGL window surface + success = graphics_get_display_size(0 /* LCD */, &rpi->mScreenWidth, &rpi->mScreenHeight); + assert(success >= 0); + + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.width = rpi->mScreenWidth; + dst_rect.height = rpi->mScreenHeight; + + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = rpi->mScreenWidth << 16; + src_rect.height = rpi->mScreenHeight << 16; + + dispman_display = vc_dispmanx_display_open(0 /* LCD */); + vc_dispmanx_display_get_info(dispman_display, &dispman_modeinfo); + dispman_update = vc_dispmanx_update_start(0); + + dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display, + 0/*layer*/, &dst_rect, 0/*src*/, + &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, DISPMANX_NO_ROTATE); + + nativewindow.element = dispman_element; + nativewindow.width = rpi->mScreenWidth; + nativewindow.height = rpi->mScreenHeight; + vc_dispmanx_update_submit_sync(dispman_update); + + rpi->mSurface = eglCreateWindowSurface(rpi->mDisplay, config, &nativewindow, NULL); + assert(rpi->mSurface != EGL_NO_SURFACE); + + // connect the context to the surface + result = eglMakeCurrent(rpi->mDisplay, rpi->mSurface, rpi->mSurface, rpi->mContext); + assert(result != EGL_FALSE); + + rpi->mBpp = video->rgb32 ? 4 : 2; + rpi->mTexType = video->rgb32 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT_5_5_5_1; + + // Set background color and clear buffers + glClearColor(0, 0, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); + glClear(GL_DEPTH_BUFFER_BIT); + //glShadeModel(GL_SMOOTH); + + // set viewport for aspect ratio, taken from RetroArch + if (video->force_aspect) + { + float desired_aspect = g_settings.video.aspect_ratio; + float device_aspect = (float) dispman_modeinfo.width / dispman_modeinfo.height; + + // If the aspect ratios of screen and desired aspect ratio are sufficiently equal (floating point stuff), + // assume they are actually equal. + if (fabs(device_aspect - desired_aspect) < 0.0001) + { + glViewport(0, 0, rpi->mScreenWidth, rpi->mScreenHeight); + } + else if (device_aspect > desired_aspect) + { + float delta = (desired_aspect / device_aspect - 1.0) / 2.0 + 0.5; + glViewport(rpi->mScreenWidth * (0.5 - delta), 0, 2.0 * rpi->mScreenWidth * delta, rpi->mScreenHeight); + rpi->mScreenWidth = 2.0 * rpi->mScreenWidth * delta; + } + else + { + float delta = (device_aspect / desired_aspect - 1.0) / 2.0 + 0.5; + glViewport(0, rpi->mScreenHeight * (0.5 - delta), rpi->mScreenWidth, 2.0 * rpi->mScreenHeight * delta); + rpi->mScreenHeight = 2.0 * rpi->mScreenHeight * delta; + } + } + else + { + glViewport(0, 0, rpi->mScreenWidth, rpi->mScreenHeight); + } + + //glMatrixMode(GL_PROJECTION); + //glLoadIdentity(); + + //glOrthof(0, 1, 0, 1, -1, 1); + //glMatrixMode(GL_MODELVIEW); + //glLoadIdentity(); + + rpi->mTextureWidth = rpi->mTextureHeight = video->input_scale * RARCH_SCALE_BASE; + + rpi->mEmptyBuf = calloc(rpi->mTextureWidth * rpi->mTextureHeight * rpi->mBpp, 1); + + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + glGenTextures(1, &rpi->mTexture); + glBindTexture(GL_TEXTURE_2D, rpi->mTexture); + //glPixelStorei(GL_UNPACK_ROW_LENGTH, mTextureWidth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rpi->mTextureWidth, rpi->mTextureHeight, 0, GL_RGBA, rpi->mTexType, rpi->mEmptyBuf); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, video->smooth ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, video->smooth ? GL_LINEAR : GL_NEAREST); + + //glEnableClientState(GL_VERTEX_ARRAY); + //glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + rpi->mTexVertices[0] = 0; + rpi->mTexVertices[1] = 1; + rpi->mTexVertices[2] = 0; + rpi->mTexVertices[3] = 0; + rpi->mTexVertices[4] = 1; + rpi->mTexVertices[5] = 0; + rpi->mTexVertices[6] = 1; + rpi->mTexVertices[7] = 1; + + //glVertexPointer(2, GL_FLOAT, 0, default_vertices); + //glTexCoordPointer(2, GL_FLOAT, 0, rpi->mTexVertices); + + rpi_setup_palette(rpi); + rpi_set_nonblock_state(rpi, video->vsync); + + return rpi; +} + +static void rpi_free(void *data) +{ + rpi_t *rpi = (rpi_t*)data; + free(rpi->mEmptyBuf); + + // clear screen + glClear(GL_COLOR_BUFFER_BIT); + eglSwapBuffers(rpi->mDisplay, rpi->mSurface); + + // Release OpenGL resources + eglMakeCurrent(rpi->mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(rpi->mDisplay, rpi->mSurface); + eglDestroyContext(rpi->mDisplay, rpi->mContext); + eglTerminate(rpi->mDisplay); + + free(rpi); +} + +static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) +{ + rpi_t *rpi = (rpi_t*)data; + (void)msg; + if (width != rpi->mRenderWidth || height != rpi->mRenderHeight) + { + rpi->mRenderWidth = width; + rpi->mRenderHeight = height; + glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(pitch)); + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, rpi->mTexType, frame); + glClear(GL_COLOR_BUFFER_BIT); + glUseProgram (rpi->program); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, default_vertices); + glEnableVertexAttribArray(0); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + eglSwapBuffers(rpi->mDisplay, rpi->mSurface); + + return true; +} + +static bool rpi_alive(void *data) +{ + (void)data; + return true; +} + +static bool rpi_focus(void *data) +{ + (void)data; + return true; +} + +static void rpi_set_rotation(void *data, unsigned rotation) +{ + (void)data; + (void)rotation; +} + +const video_driver_t video_rpi = { + rpi_init, + rpi_frame, + rpi_set_nonblock_state, + rpi_alive, + rpi_focus, + NULL, + rpi_free, + "rpi", + rpi_set_rotation, +}; diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 5382eeb8e9..7c944ffbf8 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -15,6 +15,16 @@ if [ -d /opt/local/lib ]; then add_library_dirs /opt/local/lib fi +if [ -d /opt/vc/lib ]; then + add_library_dirs /opt/vc/lib + add_include_dirs /opt/vc/include + # the gles library gets messed up with the gl library if available, so turn it off + HAVE_OPENGL=no + HAVE_RPI=yes +else + HAVE_RPI=no +fi + if [ $OS = BSD ]; then DYLIB=-lc else @@ -140,7 +150,7 @@ check_pkgconf PYTHON python3 add_define_make OS $OS # Creates config.mk and config.h. -VARS="ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL OPENGL DYLIB GETOPT_LONG THREADS CG XML SDL_IMAGE DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL SWSCALE CONFIGFILE FREETYPE XVIDEO X11 XEXT NETPLAY SOCKET_LEGACY FBO STRL 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 X264RGB SINC BSV_MOVIE" +VARS="ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL OPENGL DYLIB GETOPT_LONG THREADS CG XML SDL_IMAGE DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL SWSCALE CONFIGFILE FREETYPE XVIDEO X11 XEXT NETPLAY SOCKET_LEGACY FBO STRL 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 X264RGB SINC BSV_MOVIE RPI" create_config_make config.mk $VARS create_config_header config.h $VARS diff --git a/retroarch.c b/retroarch.c index 17a04db351..02ec29c29d 100644 --- a/retroarch.c +++ b/retroarch.c @@ -55,6 +55,10 @@ // We want to use -mconsole in Win32, so we need main(). #endif +#ifdef HAVE_RPI +#include +#endif + // To avoid continous switching if we hold the button down, we require that the button must go from pressed, unpressed back to pressed to be able to toggle between then. static void set_fast_forward_button(bool new_button_state, bool new_hold_button_state) { @@ -2518,6 +2522,9 @@ void rarch_main_deinit(void) // Consoles use the higher level API. int main(int argc, char *argv[]) { +#ifdef HAVE_RPI + bcm_host_init(); +#endif int init_ret; if ((init_ret = rarch_main_init(argc, argv))) return init_ret; while (rarch_main_iterate()); diff --git a/settings.c b/settings.c index 84d352e028..6576fc4811 100644 --- a/settings.c +++ b/settings.c @@ -91,6 +91,8 @@ const char *config_get_default_video(void) return "sdl"; case VIDEO_EXT: return "ext"; + case VIDEO_RPI: + return "rpi"; default: return NULL; } From 4e600c5edd0ae178008350105d667e8e9071bfb5 Mon Sep 17 00:00:00 2001 From: Toad King Date: Thu, 24 May 2012 01:29:35 -0400 Subject: [PATCH 02/21] Drop OpenGLES in favor of OpenVG. Video now works. Audio might work with the ALSA drivers, but SDL input is not playing nice with OpenVG/EGL. --- Makefile | 2 +- gfx/rpi.c | 300 ++++++++++-------------------------------------------- 2 files changed, 56 insertions(+), 246 deletions(-) diff --git a/Makefile b/Makefile index 893bda1415..19f845bd56 100644 --- a/Makefile +++ b/Makefile @@ -116,7 +116,7 @@ endif ifeq ($(HAVE_RPI), 1) OBJ += gfx/rpi.o - LIBS += -lGLESv2 -lEGL -lbcm_host + LIBS += -lOpenVG -lGLESv2 -lEGL -lbcm_host endif ifeq ($(HAVE_XVIDEO), 1) diff --git a/gfx/rpi.c b/gfx/rpi.c index f364260dfb..4b9c724f2f 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -1,203 +1,30 @@ #include #include #include -#include -#include +#include +#include #include #include #include "../libretro.h" #include "../general.h" -static inline unsigned get_alignment(unsigned pitch) -{ - if (pitch & 1) - return 1; - if (pitch & 2) - return 2; - if (pitch & 4) - return 4; - return 8; -} - -static const GLfloat default_vertices[] = { - 0, 0, - 0, 1, - 1, 1, - 1, 0 -}; - -typedef struct rpi { +typedef struct { EGLDisplay mDisplay; EGLSurface mSurface; EGLContext mContext; uint32_t mScreenWidth; uint32_t mScreenHeight; - GLint mTextureWidth; - GLint mTextureHeight; + unsigned mTextureWidth; + unsigned mTextureHeight; unsigned mRenderWidth; unsigned mRenderHeight; - int mBpp; - GLenum mTexType; - GLuint mTexture; - GLuint mPalette; - GLuint mVertBuf; - GLuint vshader; - GLuint fshader; - GLuint program; - GLfloat mTexVertices[8]; - uint8_t *mEmptyBuf; + unsigned x1, y1, x2, y2; + VGImageFormat mTexType; + VGImage mImage; + VGfloat mTransformMatrix[9]; + VGint scissor[4]; } rpi_t; -static uint16_t rgba1555_to_rgba5551[0x10000]; - -static void rpi_setup_palette(rpi_t *rpi) -{ - // because GLES doesn't have GL_UNSIGNED_SHORT_1_5_5_5_REV, we fake it with this shader - static const GLchar *vertex_shader_src = - "attribute vec4 vertex;\n" - "varying vec2 tcoord;\n" - "void main(void)\n" - "{\n" - "vec4 pos = vertex;\n" - "gl_Position = vertex;\n" - "tcoord = vertex.xy; // * 0.5 + 0.5;\n" - "}"; - - static const GLchar *fragment_shader_16_src = - "uniform sampler2D pal;\n" - "uniform sampler2D tex;\n" - "varying vec2 tcoord;\n" - "void main()\n" - "{\n" - "const float scale = 255.0 / 256.0;\n" - "const float offset = 0.5 / 255.0 * scale;\n" - "vec4 color = texture2D(tex, tcoord.xy);\n" - "float r = color.r / 32.0;\n" - "float g = color.g;\n" - "float b = color.b / 32.0;\n" - "float a = color.a;\n" - "float pixelx = (a + r) * scale + offset;\n" - "float pixely = (g + b) * scale + offset;\n" - "vec2 coords = vec2(pixelx, pixely);\n" - "gl_FragColor = texture2D(pal, coords);\n" - "}"; - - static const GLchar *fragment_shader_32_src = - "uniform sampler2D pal;\n" - "uniform sampler2D tex;\n" - "varying vec2 tcoord;\n" - "void main()\n" - "{\n" - "vec4 color = texture2D(tex, tcoord.xy);\n" - "gl_FragColor = vec4(color.b, color.g, color.r, color.a);\n" - "}"; - - GLint compiled, linked; - GLuint unif_pal, unif_tex; - int i, a, r, g, b; - - for(i = 0; i < 0x10000; i++) - { - a = (i & 0x8000) >> 15; - r = (i & 0x7C00) >> 9; - g = (i & 0x03E0) << 1; - b = (i & 0x001F) << 11; - rgba1555_to_rgba5551[i] = a | r | g | b; - } - - glActiveTexture(GL_TEXTURE1); - glGenTextures(1, &rpi->mPalette); - glBindTexture(GL_TEXTURE_2D, rpi->mPalette); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, rgba1555_to_rgba5551); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - rpi->vshader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(rpi->vshader, 1, &vertex_shader_src, 0); - glCompileShader(rpi->vshader); - - glGetShaderiv ( rpi->vshader, GL_COMPILE_STATUS, &compiled ); - - if ( !compiled ) - { - GLint infoLen = 0; - glGetShaderiv ( rpi->vshader, GL_INFO_LOG_LENGTH, &infoLen ); - - if ( infoLen > 1 ) - { - char* infoLog = malloc (sizeof(char) * infoLen ); - glGetShaderInfoLog ( rpi->vshader, infoLen, NULL, infoLog ); - printf ( "Error compiling shader:\n%s\n", infoLog ); - free ( infoLog ); - } - - glDeleteShader ( rpi->vshader ); - exit(1); - } - - rpi->fshader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(rpi->fshader, 1, rpi->mBpp == 2 ? &fragment_shader_16_src : &fragment_shader_32_src, 0); - glCompileShader(rpi->fshader); - - glGetShaderiv ( rpi->fshader, GL_COMPILE_STATUS, &compiled ); - - if ( !compiled ) - { - GLint infoLen = 0; - glGetShaderiv ( rpi->fshader, GL_INFO_LOG_LENGTH, &infoLen ); - - if ( infoLen > 1 ) - { - char* infoLog = malloc (sizeof(char) * infoLen ); - glGetShaderInfoLog ( rpi->fshader, infoLen, NULL, infoLog ); - printf ( "Error compiling shader:\n%s\n", infoLog ); - free ( infoLog ); - } - - glDeleteShader ( rpi->fshader ); - exit(1); - } - - rpi->program = glCreateProgram(); - glAttachShader(rpi->program, rpi->vshader); - glAttachShader(rpi->program, rpi->fshader); - glBindAttribLocation(rpi->program, 0, "vertex"); - glLinkProgram(rpi->program); - - glGetProgramiv ( rpi->program, GL_LINK_STATUS, &linked ); - if ( !linked ) - { - GLint infoLen = 0; - glGetProgramiv ( rpi->program, GL_INFO_LOG_LENGTH, &infoLen ); - - if ( infoLen > 1 ) - { - char* infoLog = malloc (sizeof(char) * infoLen ); - glGetProgramInfoLog ( rpi->program, infoLen, NULL, infoLog ); - printf( "Error linking program:\n%s\n", infoLog ); - free ( infoLog ); - } - - glDeleteProgram ( rpi->program ); - exit(1); - } - -// unif_pal = glGetUniformLocation(rpi->program, "pal"); -// unif_tex = glGetUniformLocation(rpi->program, "tex"); - -// glUniform1i(unif_pal, 1); -// glUniform1i(unif_tex, 0); - - // reset to screen texture - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, rpi->mTexture); - assert(glGetError() == 0); -} - static void rpi_set_nonblock_state(void *data, bool state) { rpi_t *rpi = (rpi_t*)data; @@ -240,6 +67,7 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v // initialize the EGL display connection result = eglInitialize(rpi->mDisplay, NULL, NULL); assert(result != EGL_FALSE); + eglBindAPI(EGL_OPENVG_API); // get an appropriate EGL frame buffer configuration result = eglChooseConfig(rpi->mDisplay, attribute_list, &config, 1, &num_config); @@ -283,14 +111,10 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v result = eglMakeCurrent(rpi->mDisplay, rpi->mSurface, rpi->mSurface, rpi->mContext); assert(result != EGL_FALSE); - rpi->mBpp = video->rgb32 ? 4 : 2; - rpi->mTexType = video->rgb32 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT_5_5_5_1; + rpi->mTexType = video->rgb32 ? VG_sXBGR_8888 : VG_sARGB_1555; - // Set background color and clear buffers - glClearColor(0, 0, 1, 1); - glClear(GL_COLOR_BUFFER_BIT); - glClear(GL_DEPTH_BUFFER_BIT); - //glShadeModel(GL_SMOOTH); + VGfloat clearColor[4] = {0, 0, 0, 1}; + vgSetfv(VG_CLEAR_COLOR, 4, clearColor); // set viewport for aspect ratio, taken from RetroArch if (video->force_aspect) @@ -302,66 +126,49 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v // assume they are actually equal. if (fabs(device_aspect - desired_aspect) < 0.0001) { - glViewport(0, 0, rpi->mScreenWidth, rpi->mScreenHeight); + rpi->x1 = 0; + rpi->y1 = 0; + rpi->x2 = rpi->mScreenWidth; + rpi->y2 = rpi->mScreenHeight; } else if (device_aspect > desired_aspect) { float delta = (desired_aspect / device_aspect - 1.0) / 2.0 + 0.5; - glViewport(rpi->mScreenWidth * (0.5 - delta), 0, 2.0 * rpi->mScreenWidth * delta, rpi->mScreenHeight); - rpi->mScreenWidth = 2.0 * rpi->mScreenWidth * delta; + rpi->x1 = rpi->mScreenWidth * (0.5 - delta); + rpi->y1 = 0; + rpi->x2 = 2.0 * rpi->mScreenWidth * delta + rpi->x1; + rpi->y2 = rpi->mScreenHeight + rpi->y1; } else { float delta = (device_aspect / desired_aspect - 1.0) / 2.0 + 0.5; - glViewport(0, rpi->mScreenHeight * (0.5 - delta), rpi->mScreenWidth, 2.0 * rpi->mScreenHeight * delta); - rpi->mScreenHeight = 2.0 * rpi->mScreenHeight * delta; + rpi->x1 = 0; + rpi->y1 = rpi->mScreenHeight * (0.5 - delta); + rpi->x2 = rpi->mScreenWidth + rpi->x1; + rpi->y2 = 2.0 * rpi->mScreenHeight * delta + rpi->y1; } } else { - glViewport(0, 0, rpi->mScreenWidth, rpi->mScreenHeight); + rpi->x1 = 0; + rpi->y1 = 0; + rpi->x2 = rpi->mScreenWidth; + rpi->y2 = rpi->mScreenHeight; } - //glMatrixMode(GL_PROJECTION); - //glLoadIdentity(); + rpi->scissor[0] = rpi->x1; + rpi->scissor[1] = rpi->y1; + rpi->scissor[2] = rpi->x2 - rpi->x1; + rpi->scissor[3] = rpi->y2 - rpi->y1; - //glOrthof(0, 1, 0, 1, -1, 1); - //glMatrixMode(GL_MODELVIEW); - //glLoadIdentity(); + vgSetiv(VG_SCISSOR_RECTS, 4, rpi->scissor); rpi->mTextureWidth = rpi->mTextureHeight = video->input_scale * RARCH_SCALE_BASE; - - rpi->mEmptyBuf = calloc(rpi->mTextureWidth * rpi->mTextureHeight * rpi->mBpp, 1); - - glEnable(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &rpi->mTexture); - glBindTexture(GL_TEXTURE_2D, rpi->mTexture); - //glPixelStorei(GL_UNPACK_ROW_LENGTH, mTextureWidth); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rpi->mTextureWidth, rpi->mTextureHeight, 0, GL_RGBA, rpi->mTexType, rpi->mEmptyBuf); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, video->smooth ? GL_LINEAR : GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, video->smooth ? GL_LINEAR : GL_NEAREST); - - //glEnableClientState(GL_VERTEX_ARRAY); - //glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - rpi->mTexVertices[0] = 0; - rpi->mTexVertices[1] = 1; - rpi->mTexVertices[2] = 0; - rpi->mTexVertices[3] = 0; - rpi->mTexVertices[4] = 1; - rpi->mTexVertices[5] = 0; - rpi->mTexVertices[6] = 1; - rpi->mTexVertices[7] = 1; - - //glVertexPointer(2, GL_FLOAT, 0, default_vertices); - //glTexCoordPointer(2, GL_FLOAT, 0, rpi->mTexVertices); - - rpi_setup_palette(rpi); + // We can't use the native format because there's no sXRGB_1555 type and + // emulation cores can send 0 in the top bit. We lose some speed on + // conversion but I doubt it has any real affect, since we are only drawing + // one image at the end of the day. + rpi->mImage = vgCreateImage(VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, VG_IMAGE_QUALITY_NONANTIALIASED); rpi_set_nonblock_state(rpi, video->vsync); return rpi; @@ -370,13 +177,10 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v static void rpi_free(void *data) { rpi_t *rpi = (rpi_t*)data; - free(rpi->mEmptyBuf); - // clear screen - glClear(GL_COLOR_BUFFER_BIT); - eglSwapBuffers(rpi->mDisplay, rpi->mSurface); + vgDestroyImage(rpi->mImage); - // Release OpenGL resources + // Release EGL resources eglMakeCurrent(rpi->mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(rpi->mDisplay, rpi->mSurface); eglDestroyContext(rpi->mDisplay, rpi->mContext); @@ -389,19 +193,25 @@ static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned he { rpi_t *rpi = (rpi_t*)data; (void)msg; + if (width != rpi->mRenderWidth || height != rpi->mRenderHeight) { rpi->mRenderWidth = width; rpi->mRenderHeight = height; - glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(pitch)); + vguComputeWarpQuadToQuad( + rpi->x1, rpi->y1, rpi->x2, rpi->y1, rpi->x2, rpi->y2, rpi->x1, rpi->y2, + // needs to be flipped, Khronos loves their bottom-left origin + 0, height, width, height, width, 0, 0, 0, + rpi->mTransformMatrix); + vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); + vgLoadMatrix(rpi->mTransformMatrix); } + vgSeti(VG_SCISSORING, VG_FALSE); + vgClear(0, 0, rpi->mScreenWidth, rpi->mScreenHeight); + vgSeti(VG_SCISSORING, VG_TRUE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, rpi->mTexType, frame); - glClear(GL_COLOR_BUFFER_BIT); - glUseProgram (rpi->program); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, default_vertices); - glEnableVertexAttribArray(0); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + vgImageSubData(rpi->mImage, frame, pitch, rpi->mTexType, 0, 0, width, height); + vgDrawImage(rpi->mImage); eglSwapBuffers(rpi->mDisplay, rpi->mSurface); From 6c79d66e1b49b6dd5b8575a0254dbd42c1142e69 Mon Sep 17 00:00:00 2001 From: Toad King Date: Fri, 25 May 2012 15:44:39 -0400 Subject: [PATCH 03/21] linuxraw input: gets input straight from stdin WARNING: this mode uses a raw keyboard mode. if the emulator does not exit cleanly, you could be left at a terminal with no form of input. do not use this mode for testing. --- Makefile | 2 + config.def.h | 1 + driver.c | 3 + driver.h | 1 + gfx/rpi.c | 13 +- input/linuxraw_input.c | 271 +++++++++++++++++++++++++++++++++++++++++ input/linuxraw_input.h | 13 ++ settings.c | 2 + 8 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 input/linuxraw_input.c create mode 100644 input/linuxraw_input.h diff --git a/Makefile b/Makefile index 19f845bd56..7052dbd32d 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,8 @@ endif ifneq ($(findstring Linux,$(OS)),) LIBS += -lrt + DEFINES += -DIS_LINUX + OBJ += input/linuxraw_input.o endif ifeq ($(HAVE_THREADS), 1) diff --git a/config.def.h b/config.def.h index 749ca8f178..895092f94c 100644 --- a/config.def.h +++ b/config.def.h @@ -63,6 +63,7 @@ #define INPUT_XENON360 21 #define INPUT_WII 23 #define INPUT_XDK360 26 +#define INPUT_LINUXRAW 30 //////////////////////// #if defined(HAVE_RPI) diff --git a/driver.c b/driver.c index 5d957c982b..1c8dc38290 100644 --- a/driver.c +++ b/driver.c @@ -123,6 +123,9 @@ static const input_driver_t *input_drivers[] = { #ifdef GEKKO &input_wii, #endif +#ifdef IS_LINUX + &input_linuxraw, +#endif }; static void find_audio_driver(void) diff --git a/driver.h b/driver.h index 5dd541f988..22cb157bc1 100644 --- a/driver.h +++ b/driver.h @@ -211,6 +211,7 @@ extern const input_driver_t input_ps3; extern const input_driver_t input_xenon360; extern const input_driver_t input_wii; extern const input_driver_t input_xdk360; +extern const input_driver_t input_linuxraw; //////////////////////////////////////////////// // Convenience macros. diff --git a/gfx/rpi.c b/gfx/rpi.c index 4b9c724f2f..33cc016ceb 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -7,6 +7,8 @@ #include #include "../libretro.h" #include "../general.h" +#include "../input/linuxraw_input.h" +#include "../driver.h" typedef struct { EGLDisplay mDisplay; @@ -28,7 +30,7 @@ typedef struct { static void rpi_set_nonblock_state(void *data, bool state) { rpi_t *rpi = (rpi_t*)data; - eglSwapInterval(rpi->mDisplay, state ? 1 : 0); + eglSwapInterval(rpi->mDisplay, state ? 0 : 1); } static void *rpi_init(const video_info_t *video, const input_driver_t **input, void **input_data) @@ -170,6 +172,15 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v // one image at the end of the day. rpi->mImage = vgCreateImage(VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, VG_IMAGE_QUALITY_NONANTIALIASED); rpi_set_nonblock_state(rpi, video->vsync); + + linuxraw_input_t *linuxraw_input = (linuxraw_input_t*)input_linuxraw.init(); + if (linuxraw_input) + { + *input = &input_linuxraw; + *input_data = linuxraw_input; + } + else + *input = NULL; return rpi; } diff --git a/input/linuxraw_input.c b/input/linuxraw_input.c new file mode 100644 index 0000000000..a1c5af9e53 --- /dev/null +++ b/input/linuxraw_input.c @@ -0,0 +1,271 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2012 - 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 +#include +#include +#include +#include "../general.h" +#include "linuxraw_input.h" +#include "rarch_sdl_input.h" + +static long oldKbmd = 0xFFFF; +static struct termios oldTerm, newTerm; + +struct key_bind +{ + uint8_t x; + enum rarch_key sk; +}; + +static unsigned keysym_lut[SK_LAST]; +static const struct key_bind lut_binds[] = { + { 1, SK_ESCAPE }, + { 2, SK_1 }, + { 3, SK_2 }, + { 4, SK_3}, + { 5, SK_4 }, + { 6, SK_5 }, + { 7, SK_6 }, + { 8, SK_7 }, + { 9, SK_8 }, + { 10, SK_9 }, + { 11, SK_0 }, + { 12, SK_MINUS }, + { 13, SK_EQUALS }, + { 14, SK_BACKSPACE }, + { 15, SK_TAB }, + { 16, SK_q }, + { 17, SK_w }, + { 18, SK_e }, + { 19, SK_r }, + { 20, SK_t }, + { 21, SK_y }, + { 22, SK_u }, + { 23, SK_i }, + { 24, SK_o }, + { 25, SK_p }, + { 26, SK_LEFTBRACKET }, + { 27, SK_RIGHTBRACKET }, + { 28, SK_RETURN }, + { 29, SK_LCTRL }, + { 30, SK_a }, + { 31, SK_s }, + { 32, SK_d }, + { 33, SK_f }, + { 34, SK_g }, + { 35, SK_h }, + { 36, SK_j }, + { 37, SK_k }, + { 38, SK_l }, + { 39, SK_SEMICOLON }, + { 40, SK_COMMA }, + { 41, SK_BACKQUOTE }, + { 42, SK_LSHIFT }, + { 43, SK_BACKSLASH }, + { 44, SK_z }, + { 45, SK_x }, + { 46, SK_c }, + { 47, SK_v }, + { 48, SK_b }, + { 49, SK_n }, + { 50, SK_m }, + { 51, SK_COMMA }, + { 52, SK_PERIOD }, + { 53, SK_SLASH }, + { 54, SK_RSHIFT }, + { 55, SK_KP_MULTIPLY }, + { 56, SK_LALT }, + { 57, SK_SPACE }, + { 58, SK_CAPSLOCK }, + { 59, SK_F1 }, + { 60, SK_F2 }, + { 61, SK_F3 }, + { 62, SK_F4 }, + { 63, SK_F5 }, + { 64, SK_F6 }, + { 65, SK_F7 }, + { 66, SK_F8 }, + { 67, SK_F9 }, + { 68, SK_F10 }, + { 69, SK_NUMLOCK }, + { 70, SK_SCROLLOCK }, + { 71, SK_KP7 }, + { 72, SK_KP8 }, + { 73, SK_KP9 }, + { 74, SK_KP_MINUS }, + { 75, SK_KP4 }, + { 76, SK_KP5 }, + { 77, SK_KP6 }, + { 78, SK_KP_PLUS }, + { 79, SK_KP1 }, + { 80, SK_KP2 }, + { 81, SK_KP3 }, + { 82, SK_KP0 }, + { 83, SK_KP_PERIOD }, + + { 87, SK_F11 }, + { 88, SK_F12 }, + + { 96, SK_KP_ENTER }, + { 97, SK_RCTRL }, + { 98, SK_KP_DIVIDE }, + { 99, SK_PRINT }, + { 100, SK_RALT }, + + { 102, SK_HOME }, + { 103, SK_UP }, + { 104, SK_PAGEUP }, + { 105, SK_LEFT }, + { 106, SK_RIGHT }, + { 107, SK_END }, + { 108, SK_DOWN }, + { 109, SK_PAGEDOWN }, + { 110, SK_INSERT }, + { 111, SK_DELETE }, + + { 119, SK_PAUSE }, +}; + +static void init_lut(void) +{ + memset(keysym_lut, 0, sizeof(keysym_lut)); + for (unsigned i = 0; i < sizeof(lut_binds) / sizeof(lut_binds[0]); i++) + keysym_lut[lut_binds[i].sk] = lut_binds[i].x; +} + +static void linuxraw_resetKbmd() +{ + if (oldKbmd != 0xFFFF) + { + ioctl(0, KDSKBMODE, oldKbmd); + tcsetattr(0, TCSAFLUSH, &oldTerm); + oldKbmd = 0xFFFF; + } +} + +static void *linuxraw_input_init(void) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)calloc(1, sizeof(*linuxraw)); + if (!linuxraw) + return NULL; + + if (oldKbmd == 0xFFFF) + { + tcgetattr(0, &oldTerm); + newTerm = oldTerm; + newTerm.c_lflag &= ~(ECHO | ICANON | ISIG); + newTerm.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); + newTerm.c_cc[VMIN] = 0; + newTerm.c_cc[VTIME] = 0; + + if (ioctl(0, KDGKBMODE, &oldKbmd) != 0) + return NULL; + } + + tcsetattr(0, TCSAFLUSH, &newTerm); + + if (ioctl(0, KDSKBMODE, K_MEDIUMRAW) != 0) + { + linuxraw_resetKbmd(); + return NULL; + } + + atexit(linuxraw_resetKbmd); + + linuxraw->sdl = (sdl_input_t*)input_sdl.init(); + if (!linuxraw->sdl) + { + free(linuxraw); + return NULL; + } + + init_lut(); + + linuxraw->sdl->use_keyboard = false; + return linuxraw; +} + +static bool linuxraw_key_pressed(linuxraw_input_t *linuxraw, int key) +{ + return linuxraw->state[keysym_lut[key]]; +} + +static bool linuxraw_is_pressed(linuxraw_input_t *linuxraw, const struct snes_keybind *binds, unsigned id) +{ + if (id < RARCH_BIND_LIST_END) + { + const struct snes_keybind *bind = &binds[id]; + return bind->valid && linuxraw_key_pressed(linuxraw, binds[id].key); + } + else + return false; +} + +static bool linuxraw_bind_button_pressed(void *data, int key) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + return linuxraw_is_pressed(linuxraw, g_settings.input.binds[0], key) || + input_sdl.key_pressed(linuxraw->sdl, key); +} + +static int16_t linuxraw_input_state(void *data, const struct snes_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + + switch (device) + { + case RETRO_DEVICE_JOYPAD: + return linuxraw_is_pressed(linuxraw, binds[port], id) || + input_sdl.input_state(linuxraw->sdl, binds, port, device, index, id); + + default: + return 0; + } +} + +static void linuxraw_input_free(void *data) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + input_sdl.free(linuxraw->sdl); + linuxraw_resetKbmd(); + free(data); +} + +static void linuxraw_input_poll(void *data) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + uint8_t c; + + while (read(0, &c, 1)) + { + bool pressed = !(c & 0x80); + c &= ~0x80; + linuxraw->state[c] = pressed; + } + + input_sdl.poll(linuxraw->sdl); +} + +const input_driver_t input_linuxraw = { + linuxraw_input_init, + linuxraw_input_poll, + linuxraw_input_state, + linuxraw_bind_button_pressed, + linuxraw_input_free, + "linuxraw" +}; diff --git a/input/linuxraw_input.h b/input/linuxraw_input.h new file mode 100644 index 0000000000..a75caf03bb --- /dev/null +++ b/input/linuxraw_input.h @@ -0,0 +1,13 @@ +#include "../general.h" +#include "rarch_sdl_input.h" + +#ifndef _LINUXRAW_INPUT_H +#define _LINUXRAW_INPUT_H + +typedef struct linuxraw_input +{ + sdl_input_t *sdl; + bool state[0x80]; +} linuxraw_input_t; + +#endif diff --git a/settings.c b/settings.c index 6576fc4811..3895ffd5cb 100644 --- a/settings.c +++ b/settings.c @@ -114,6 +114,8 @@ const char *config_get_default_input(void) return "xdk360"; case INPUT_WII: return "wii"; + case INPUT_LINUXRAW: + return "linuxraw"; default: return NULL; } From 38ceb89ce47906bb4db8566bd127cff9d09d1abc Mon Sep 17 00:00:00 2001 From: Toad King Date: Fri, 25 May 2012 16:07:11 -0400 Subject: [PATCH 04/21] set vsync correctly first time --- gfx/rpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/rpi.c b/gfx/rpi.c index 33cc016ceb..612ad03676 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -171,7 +171,7 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v // conversion but I doubt it has any real affect, since we are only drawing // one image at the end of the day. rpi->mImage = vgCreateImage(VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, VG_IMAGE_QUALITY_NONANTIALIASED); - rpi_set_nonblock_state(rpi, video->vsync); + rpi_set_nonblock_state(rpi, !video->vsync); linuxraw_input_t *linuxraw_input = (linuxraw_input_t*)input_linuxraw.init(); if (linuxraw_input) From c0050a7c8b704e72ac024ef90277768407dac923 Mon Sep 17 00:00:00 2001 From: Toad King Date: Fri, 25 May 2012 18:12:07 -0400 Subject: [PATCH 05/21] Don't use linuxraw input if the user isn't running RetroArch from a terminal --- gfx/rpi.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/gfx/rpi.c b/gfx/rpi.c index 612ad03676..5eaf84d86f 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -172,15 +173,16 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v // one image at the end of the day. rpi->mImage = vgCreateImage(VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, VG_IMAGE_QUALITY_NONANTIALIASED); rpi_set_nonblock_state(rpi, !video->vsync); - - linuxraw_input_t *linuxraw_input = (linuxraw_input_t*)input_linuxraw.init(); - if (linuxraw_input) + + if (isatty(0)) { - *input = &input_linuxraw; - *input_data = linuxraw_input; + linuxraw_input_t *linuxraw_input = (linuxraw_input_t*)input_linuxraw.init(); + if (linuxraw_input) + { + *input = &input_linuxraw; + *input_data = linuxraw_input; + } } - else - *input = NULL; return rpi; } From 2cb3ae3476c8b80a0c43f3f34eba2a5731b89220 Mon Sep 17 00:00:00 2001 From: Toad King Date: Fri, 25 May 2012 20:38:14 -0400 Subject: [PATCH 06/21] Change quality for smooth setting Keep alpha channel for rgb32 mode --- gfx/rpi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gfx/rpi.c b/gfx/rpi.c index 5eaf84d86f..52dc73ec6e 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -114,7 +114,7 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v result = eglMakeCurrent(rpi->mDisplay, rpi->mSurface, rpi->mSurface, rpi->mContext); assert(result != EGL_FALSE); - rpi->mTexType = video->rgb32 ? VG_sXBGR_8888 : VG_sARGB_1555; + rpi->mTexType = video->rgb32 ? VG_sABGR_8888 : VG_sARGB_1555; VGfloat clearColor[4] = {0, 0, 0, 1}; vgSetfv(VG_CLEAR_COLOR, 4, clearColor); @@ -170,8 +170,8 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v // We can't use the native format because there's no sXRGB_1555 type and // emulation cores can send 0 in the top bit. We lose some speed on // conversion but I doubt it has any real affect, since we are only drawing - // one image at the end of the day. - rpi->mImage = vgCreateImage(VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, VG_IMAGE_QUALITY_NONANTIALIASED); + // one image at the end of the day. Still keep the alpha channel for ABGR. + rpi->mImage = vgCreateImage(video->rgb32 ? VG_sABGR_8888 : VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, video->smooth ? VG_IMAGE_QUALITY_BETTER : VG_IMAGE_QUALITY_NONANTIALIASED); rpi_set_nonblock_state(rpi, !video->vsync); if (isatty(0)) From eaff0d0f388474a146df6e596a6f70167c3c6d85 Mon Sep 17 00:00:00 2001 From: Toad King Date: Mon, 28 May 2012 06:33:13 -0400 Subject: [PATCH 07/21] Added messages support to the Raspberry Pi video driver --- gfx/rpi.c | 388 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 385 insertions(+), 3 deletions(-) diff --git a/gfx/rpi.c b/gfx/rpi.c index 52dc73ec6e..94d76eaaf2 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -8,9 +8,20 @@ #include #include "../libretro.h" #include "../general.h" -#include "../input/linuxraw_input.h" +//#include "../input/linuxraw_input.h" +// SDL include messing with some defines +typedef struct linuxraw_input linuxraw_input_t; #include "../driver.h" +#ifdef HAVE_FREETYPE +#include +#include +#include FT_FREETYPE_H +#include FT_OUTLINE_H +#include "../file.h" +#endif + + typedef struct { EGLDisplay mDisplay; EGLSurface mSurface; @@ -26,6 +37,19 @@ typedef struct { VGImage mImage; VGfloat mTransformMatrix[9]; VGint scissor[4]; + +#ifdef HAVE_FREETYPE + char *mLastMsg; + uint32_t mFontHeight; + FT_Library ftLib; + FT_Face ftFace; + VGFont mFont; + bool mFontsOn; + VGuint mMsgLength; + VGuint mGlyphIndices[1024]; + VGPaint mPaintFg; + VGPaint mPaintBg; +#endif } rpi_t; static void rpi_set_nonblock_state(void *data, bool state) @@ -176,14 +200,99 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v if (isatty(0)) { - linuxraw_input_t *linuxraw_input = (linuxraw_input_t*)input_linuxraw.init(); + const linuxraw_input_t *linuxraw_input = (const linuxraw_input_t *) input_linuxraw.init(); if (linuxraw_input) { - *input = &input_linuxraw; + *input = (const input_driver_t *) &input_linuxraw; *input_data = linuxraw_input; } } +#ifdef HAVE_FREETYPE + + static const char *font_paths[] = { +#if defined(_WIN32) + "C:\\Windows\\Fonts\\consola.ttf", + "C:\\Windows\\Fonts\\verdana.ttf", +#elif defined(__APPLE__) + "/Library/Fonts/Microsoft/Candara.ttf", + "/Library/Fonts/Verdana.ttf", + "/Library/Fonts/Tahoma.ttf", +#else + "/usr/share/fonts/TTF/DejaVuSansMono.ttf", + "/usr/share/fonts/TTF/DejaVuSans.ttf", +#endif + "osd-font.ttf", // Magic font to search for, useful for distribution. + }; + + const char *font = g_settings.video.font_path; + + if (!g_settings.video.font_enable) + goto fail; + + if (!path_file_exists(font)) + { + font = NULL; + + for (int i = 0; i < sizeof(font_paths) / sizeof(font_paths[0]); i++) + { + if (path_file_exists(font_paths[i])) + { + font = font_paths[i]; + break; + } + } + } + + if (!font) + { + RARCH_WARN("No font found, messages disabled...\n"); + goto fail; + } + + if (FT_Init_FreeType(&rpi->ftLib)) { + RARCH_WARN("failed to initialize freetype\n"); + goto fail; + } + + if (FT_New_Face(rpi->ftLib, font, 0, &rpi->ftFace)) { + RARCH_WARN("failed to load %s\n", font); + goto fail; + } + + if (FT_Select_Charmap(rpi->ftFace, FT_ENCODING_UNICODE)) { + RARCH_WARN("failed to select an unicode charmap\n"); + goto fail; + } + + uint32_t size = g_settings.video.font_size * (g_settings.video.font_scale ? (float) rpi->mScreenWidth / 1280.0f : 1.0f); + rpi->mFontHeight = size; + + if (FT_Set_Pixel_Sizes(rpi->ftFace, size, size)) + RARCH_WARN("failed to set pixel sizes\n"); + + rpi->mFont = vgCreateFont(0); + + if (rpi->mFont) + rpi->mFontsOn = true; + + rpi->mPaintFg = vgCreatePaint(); + rpi->mPaintBg = vgCreatePaint(); + VGfloat paintFg[] = { g_settings.video.msg_color_r, g_settings.video.msg_color_g, g_settings.video.msg_color_b, 1.0f }; + VGfloat paintBg[] = { g_settings.video.msg_color_r / 2.0f, g_settings.video.msg_color_g / 2.0f, g_settings.video.msg_color_b / 2.0f, 0.5f }; + + vgSetParameteri(rpi->mPaintFg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(rpi->mPaintFg, VG_PAINT_COLOR, 4, paintFg); + + vgSetParameteri(rpi->mPaintBg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(rpi->mPaintBg, VG_PAINT_COLOR, 4, paintBg); + +// vgSetPaint(myFillPaint, VG_FILL_PATH); +// vgSetPaint(myStrokePaint, VG_STROKE_PATH); + + fail: +#endif + return rpi; } @@ -202,6 +311,274 @@ static void rpi_free(void *data) free(rpi); } +#ifdef HAVE_FREETYPE + +// mostly adapted from example code in Mesa-3d + +static int path_append(VGPath path, VGubyte segment, const FT_Vector **vectors) +{ + VGfloat coords[6]; + int i, num_vectors; + + switch (segment) + { + case VG_MOVE_TO: + case VG_LINE_TO: + num_vectors = 1; + break; + case VG_QUAD_TO: + num_vectors = 2; + break; + case VG_CUBIC_TO: + num_vectors = 3; + break; + default: + return -1; + break; + } + + for (i = 0; i < num_vectors; i++) + { + coords[2 * i + 0] = (float) vectors[i]->x / 64.0f; + coords[2 * i + 1] = (float) vectors[i]->y / 64.0f; + } + + vgAppendPathData(path, 1, &segment, (const void *) coords); + + return 0; +} + +static int decompose_move_to(const FT_Vector *to, void *user) +{ + VGPath path = (VGPath) (VGuint) user; + + return path_append(path, VG_MOVE_TO, &to); +} + +static int decompose_line_to(const FT_Vector *to, void *user) +{ + VGPath path = (VGPath) (VGuint) user; + + return path_append(path, VG_LINE_TO, &to); +} + +static int decompose_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) +{ + VGPath path = (VGPath) (VGuint) user; + const FT_Vector *vectors[2] = { control, to }; + + return path_append(path, VG_QUAD_TO, vectors); +} + +static int decompose_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) +{ + VGPath path = (VGPath) (VGuint) user; + const FT_Vector *vectors[3] = { control1, control2, to }; + + return path_append(path, VG_CUBIC_TO, vectors); +} + +static VGHandle convert_outline_glyph(rpi_t *rpi) +{ + FT_GlyphSlot glyph = rpi->ftFace->glyph; + FT_Outline_Funcs funcs = { + decompose_move_to, + decompose_line_to, + decompose_conic_to, + decompose_cubic_to, + 0, 0 + }; + + VGHandle path; + + path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, glyph->outline.n_points, VG_PATH_CAPABILITY_ALL); + + if (FT_Outline_Decompose(&glyph->outline, &funcs, (void *) (VGuint) path)) + { + vgDestroyPath(path); + path = VG_INVALID_HANDLE; + } + + return path; +} + +static VGint glyph_string_add_path(rpi_t *rpi, VGPath path, const VGfloat origin[2], VGfloat escapement[2]) +{ + if (rpi->mMsgLength >= 1024) + return -1; + + if (rpi->mFont != VG_INVALID_HANDLE) + { + vgSetGlyphToPath(rpi->mFont, rpi->mMsgLength, path, VG_TRUE, origin, escapement); + return rpi->mMsgLength++; + } + + return -1; +} + +static VGHandle convert_bitmap_glyph(rpi_t *rpi) +{ + FT_GlyphSlot glyph = rpi->ftFace->glyph; + VGImage image; + VGint width, height, stride; + unsigned char *data; + int i, j; + + switch (glyph->bitmap.pixel_mode) + { + case FT_PIXEL_MODE_MONO: + case FT_PIXEL_MODE_GRAY: + break; + default: + return VG_INVALID_HANDLE; + break; + } + + data = glyph->bitmap.buffer; + width = glyph->bitmap.width; + height = glyph->bitmap.rows; + stride = glyph->bitmap.pitch; + + /* mono to gray, and flip if needed */ + if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) + { + data = malloc(width * height); + if (!data) + return VG_INVALID_HANDLE; + + for (i = 0; i < height; i++) + { + unsigned char *dst = &data[width * i]; + const unsigned char *src; + + if (stride > 0) + src = glyph->bitmap.buffer + stride * (height - i - 1); + else + src = glyph->bitmap.buffer - stride * i; + + for (j = 0; j < width; j++) + { + if (src[j / 8] & (1 << (7 - (j % 8)))) + dst[j] = 0xff; + else + dst[j] = 0x0; + } + } + stride = -width; + } + + image = vgCreateImage(VG_A_8, width, height, VG_IMAGE_QUALITY_NONANTIALIASED); + + if (stride < 0) + { + stride = -stride; + vgImageSubData(image, data, stride, VG_A_8, 0, 0, width, height); + } + else + { + /* flip vertically */ + for (i = 0; i < height; i++) + { + const unsigned char *row = data + stride * i; + + vgImageSubData(image, row, stride, VG_A_8, 0, height - i - 1, width, 1); + } + } + + if (data != glyph->bitmap.buffer) + free(data); + + return (VGHandle) image; +} + +static VGint glyph_string_add_image(rpi_t *rpi, VGImage image, const VGfloat origin[2], VGfloat escapement[2]) +{ + if (rpi->mMsgLength >= 1024) + return -1; + + if (rpi->mFont != VG_INVALID_HANDLE) + { + vgSetGlyphToImage(rpi->mFont, rpi->mMsgLength, image, origin, escapement); + return rpi->mMsgLength++; + } + + return -1; +} + +static void rpi_draw_message(rpi_t *rpi, const char *msg) +{ + if (!rpi->mLastMsg || strcmp(rpi->mLastMsg, msg)) + { + if (rpi->mLastMsg) + free(rpi->mLastMsg); + + rpi->mLastMsg = strdup(msg); + + if(rpi->mMsgLength) + while (--rpi->mMsgLength) + vgClearGlyph(rpi->mFont, rpi->mMsgLength); + + rpi->mMsgLength = 0; + + for (int i = 0; msg[i]; i++) + { + VGfloat origin[2], escapement[2]; + VGHandle handle; + + /* + * if a character appears more than once, it will be loaded and converted + * again... + */ + if (FT_Load_Char(rpi->ftFace, msg[i], FT_LOAD_DEFAULT)) + { + RARCH_WARN("failed to load glyph '%c'\n", msg[i]); + goto fail; + } + + escapement[0] = (VGfloat) rpi->ftFace->glyph->advance.x / 64.0f; + escapement[1] = (VGfloat) rpi->ftFace->glyph->advance.y / 64.0f; + + switch (rpi->ftFace->glyph->format) + { + case FT_GLYPH_FORMAT_OUTLINE: + handle = convert_outline_glyph(rpi); + origin[0] = 0.0f; + origin[1] = 0.0f; + glyph_string_add_path(rpi, (VGPath) handle, origin, escapement); + break; + case FT_GLYPH_FORMAT_BITMAP: + handle = convert_bitmap_glyph(rpi); + origin[0] = (VGfloat) (-rpi->ftFace->glyph->bitmap_left); + origin[1] = (VGfloat) (rpi->ftFace->glyph->bitmap.rows - rpi->ftFace->glyph->bitmap_top); + glyph_string_add_image(rpi, (VGImage) handle, origin, escapement); + break; + default: + break; + } + } + for (int i = 0; i < rpi->mMsgLength; i++) + rpi->mGlyphIndices[i] = i; + } + + fail: + + vgSeti(VG_SCISSORING, VG_FALSE); + + VGfloat origins[] = { rpi->mScreenWidth * g_settings.video.msg_pos_x - 2.0f, rpi->mScreenHeight * g_settings.video.msg_pos_y - 2.0f }; + vgSetfv(VG_GLYPH_ORIGIN, 2, origins); + vgSetPaint(rpi->mPaintBg, VG_FILL_PATH); + vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE); + origins[0] += 2.0f; + origins[1] += 2.0f; + vgSetfv(VG_GLYPH_ORIGIN, 2, origins); + vgSetPaint(rpi->mPaintFg, VG_FILL_PATH); + vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE); + + vgSeti(VG_SCISSORING, VG_TRUE); +} + +#endif + static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) { rpi_t *rpi = (rpi_t*)data; @@ -226,6 +603,11 @@ static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned he vgImageSubData(rpi->mImage, frame, pitch, rpi->mTexType, 0, 0, width, height); vgDrawImage(rpi->mImage); +#ifdef HAVE_FREETYPE + if (msg && rpi->mFontsOn) + rpi_draw_message(rpi, msg); +#endif + eglSwapBuffers(rpi->mDisplay, rpi->mSurface); return true; From 619db3a04739d9692a164e36d5781b549e85c9c7 Mon Sep 17 00:00:00 2001 From: Toad King Date: Mon, 28 May 2012 07:53:39 -0400 Subject: [PATCH 08/21] change default font paths to point to Debian font location --- gfx/rpi.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/gfx/rpi.c b/gfx/rpi.c index 94d76eaaf2..78c9b31805 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -211,17 +211,8 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v #ifdef HAVE_FREETYPE static const char *font_paths[] = { -#if defined(_WIN32) - "C:\\Windows\\Fonts\\consola.ttf", - "C:\\Windows\\Fonts\\verdana.ttf", -#elif defined(__APPLE__) - "/Library/Fonts/Microsoft/Candara.ttf", - "/Library/Fonts/Verdana.ttf", - "/Library/Fonts/Tahoma.ttf", -#else - "/usr/share/fonts/TTF/DejaVuSansMono.ttf", - "/usr/share/fonts/TTF/DejaVuSans.ttf", -#endif + "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf", + "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", "osd-font.ttf", // Magic font to search for, useful for distribution. }; From 8833bd0fd1297c1708f71c2e258efed8d0452e22 Mon Sep 17 00:00:00 2001 From: Toad King Date: Thu, 31 May 2012 10:54:50 -0400 Subject: [PATCH 09/21] code cleanup --- gfx/rpi.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/gfx/rpi.c b/gfx/rpi.c index 78c9b31805..513fa49062 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -278,9 +278,6 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v vgSetParameteri(rpi->mPaintBg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); vgSetParameterfv(rpi->mPaintBg, VG_PAINT_COLOR, 4, paintBg); -// vgSetPaint(myFillPaint, VG_FILL_PATH); -// vgSetPaint(myStrokePaint, VG_STROKE_PATH); - fail: #endif @@ -509,8 +506,6 @@ static void rpi_draw_message(rpi_t *rpi, const char *msg) while (--rpi->mMsgLength) vgClearGlyph(rpi->mFont, rpi->mMsgLength); - rpi->mMsgLength = 0; - for (int i = 0; msg[i]; i++) { VGfloat origin[2], escapement[2]; @@ -573,7 +568,6 @@ static void rpi_draw_message(rpi_t *rpi, const char *msg) static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) { rpi_t *rpi = (rpi_t*)data; - (void)msg; if (width != rpi->mRenderWidth || height != rpi->mRenderHeight) { @@ -597,6 +591,8 @@ static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned he #ifdef HAVE_FREETYPE if (msg && rpi->mFontsOn) rpi_draw_message(rpi, msg); +#else + (void)msg; #endif eglSwapBuffers(rpi->mDisplay, rpi->mSurface); From 217b0157f3b79ea9fb926bc8408139a7d320c16a Mon Sep 17 00:00:00 2001 From: Toad King Date: Thu, 7 Jun 2012 20:24:06 -0400 Subject: [PATCH 10/21] fixes for new Raspberry Pi SDK --- qb/config.libs.sh | 1 + qb/config.libs.sh.orig | 164 ----------------------------------------- 2 files changed, 1 insertion(+), 164 deletions(-) delete mode 100644 qb/config.libs.sh.orig diff --git a/qb/config.libs.sh b/qb/config.libs.sh index c77ac8cda6..f0d3c950f5 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -18,6 +18,7 @@ fi if [ -d /opt/vc/lib ]; then add_library_dirs /opt/vc/lib add_include_dirs /opt/vc/include + add_include_dirs /opt/vc/include/interface/vcos/pthreads # the gles library gets messed up with the gl library if available, so turn it off HAVE_OPENGL=no HAVE_RPI=yes diff --git a/qb/config.libs.sh.orig b/qb/config.libs.sh.orig deleted file mode 100644 index 725209f911..0000000000 --- a/qb/config.libs.sh.orig +++ /dev/null @@ -1,164 +0,0 @@ -. qb/qb.libs.sh - -check_switch_c C99 -std=gnu99 -check_critical C99 "Cannot find C99 compatible compiler." - -check_switch_c NOUNUSED -Wno-unused-result -add_define_make NOUNUSED $HAVE_NOUNUSED - -# There are still broken 64-bit Linux distros out there. :) -if [ -d /usr/lib64 ]; then - add_library_dirs /usr/lib64 -fi - -if [ -d /opt/local/lib ]; then - add_library_dirs /opt/local/lib -fi - -if [ -d /opt/vc/lib ]; then - add_library_dirs /opt/vc/lib - add_include_dirs /opt/vc/include - # the gles library gets messed up with the gl library if available, so turn it off - HAVE_OPENGL=no - HAVE_RPI=yes -else - HAVE_RPI=no -fi - -if [ $OS = BSD ]; then - DYLIB=-lc -else - DYLIB=-ldl -fi - -if [ -z "$LIBRETRO" ]; then - LIBRETRO="-lretro" -else - echo "Explicit libsnes used, disabling dynamic libsnes loading ..." - HAVE_DYNAMIC=no -fi - -if [ $HAVE_DYNAMIC != yes ]; then - check_lib_cxx RETRO $LIBRETRO retro_init $DYLIB - check_critical RETRO "Cannot find libretro." - add_define_make libretro $LIBRETRO -fi - -check_lib THREADS -lpthread pthread_create -check_lib DYLIB $DYLIB dlopen - -check_lib NETPLAY -lc socket -if [ $HAVE_NETPLAY = yes ]; then - HAVE_GETADDRINFO=auto - check_lib GETADDRINFO -lc getaddrinfo - if [ $HAVE_GETADDRINFO = yes ]; then - HAVE_SOCKET_LEGACY=no - else - HAVE_SOCKET_LEGACY=yes - fi - HAVE_NETWORK_CMD=yes -else - HAVE_NETWORK_CMD=no -fi - - -check_lib GETOPT_LONG -lc getopt_long - -if [ $HAVE_DYLIB = no ] && [ $HAVE_DYNAMIC = yes ]; then - echo "Dynamic loading of libsnes is enabled, but your platform does not appear to have dlopen(), use --disable-dynamic or --with-libsnes=\"-lsnes\"". - exit 1 -fi - -check_pkgconf ALSA alsa -check_header OSS sys/soundcard.h -check_header OSS_BSD soundcard.h -check_lib OSS_LIB -lossaudio - -if [ $OS = Darwin ]; then - check_lib AL "-framework OpenAL" alcOpenDevice -else - check_lib AL -lopenal alcOpenDevice -fi - -if [ $OS = Darwin ]; then - check_lib FBO "-framework OpenGL" glFramebufferTexture2D -else - check_lib FBO -lGL glFramebufferTexture2D -fi - -check_pkgconf RSOUND rsound 1.1 -check_pkgconf ROAR libroar -check_pkgconf JACK jack 0.120.1 -check_pkgconf PULSE libpulse - -check_lib COREAUDIO "-framework AudioUnit" AudioUnitInitialize - -check_pkgconf SDL sdl 1.2.10 -check_critical SDL "Cannot find SDL library." - -# On some distros, -lCg doesn't link against -lstdc++ it seems ... -if [ $HAVE_OPENGL != no ]; then - check_lib_cxx CG -lCg cgCreateContext -else - echo "Ignoring Cg. OpenGL is not enabled." - HAVE_CG=no -fi - -check_pkgconf XML libxml-2.0 -check_pkgconf SDL_IMAGE SDL_image - -if [ $HAVE_THREADS != no ]; then - if [ $HAVE_FFMPEG != no ]; then - check_pkgconf AVCODEC libavcodec - check_pkgconf AVFORMAT libavformat - check_pkgconf AVUTIL libavutil - check_pkgconf SWSCALE libswscale - - ( [ $HAVE_FFMPEG = auto ] && ( [ $HAVE_AVCODEC = no ] || [ $HAVE_AVFORMAT = no ] || [ $HAVE_AVUTIL = no ] || [ $HAVE_SWSCALE = no ] ) && HAVE_FFMPEG=no ) || HAVE_FFMPEG=yes - fi - - if [ $HAVE_FFMPEG = yes ]; then - check_lib FFMPEG_ALLOC_CONTEXT3 "$AVCODEC_LIBS" avcodec_alloc_context3 - check_lib FFMPEG_AVCODEC_OPEN2 "$AVCODEC_LIBS" avcodec_open2 - check_lib FFMPEG_AVCODEC_ENCODE_AUDIO2 "$AVCODEC_LIBS" avcodec_encode_audio2 - check_lib FFMPEG_AVIO_OPEN "$AVFORMAT_LIBS" avio_open - check_lib FFMPEG_AVFORMAT_WRITE_HEADER "$AVFORMAT_LIBS" avformat_write_header - check_lib FFMPEG_AVFORMAT_NEW_STREAM "$AVFORMAT_LIBS" avformat_new_stream - check_lib FFMPEG_AVCODEC_ENCODE_VIDEO2 "$AVCODEC_LIBS" avcodec_encode_video2 - fi - - if [ $HAVE_FFMPEG = no ] && [ $HAVE_X264RGB = yes ]; then - echo "x264 RGB recording is enabled, but FFmpeg is not. --enable-x264rgb will not have any effect." - fi -else - echo "Not building with threading support. Will skip FFmpeg." - HAVE_FFMPEG=no -fi - -check_lib DYNAMIC $DYLIB dlopen - -check_pkgconf FREETYPE freetype2 -check_pkgconf X11 x11 -check_pkgconf XEXT xext -if [ $HAVE_X11 = yes ] && [ $HAVE_XEXT = yes ]; then - check_pkgconf XVIDEO xv -else - echo "X11 or Xext not present. Skipping XVideo." - HAVE_XVIDEO=no -fi - -check_lib STRL -lc strlcpy - -check_pkgconf PYTHON python3 - -add_define_make OS $OS - -# Creates config.mk and config.h. -<<<<<<< HEAD -VARS="ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL OPENGL DYLIB GETOPT_LONG THREADS CG XML SDL_IMAGE DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL SWSCALE CONFIGFILE FREETYPE XVIDEO X11 XEXT NETPLAY SOCKET_LEGACY FBO STRL 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 X264RGB SINC BSV_MOVIE RPI" -======= -VARS="ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL OPENGL DYLIB GETOPT_LONG THREADS CG XML SDL_IMAGE DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL SWSCALE CONFIGFILE FREETYPE XVIDEO X11 XEXT NETPLAY NETWORK_CMD SOCKET_LEGACY FBO STRL 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 X264RGB SINC BSV_MOVIE" ->>>>>>> 232cf0d1224d219cb496316ee95c55bdde92ab25 -create_config_make config.mk $VARS -create_config_header config.h $VARS - From e1b58ca683453828166d710f73c9e184750faad7 Mon Sep 17 00:00:00 2001 From: Toad King Date: Thu, 14 Jun 2012 03:04:17 -0400 Subject: [PATCH 11/21] calculate aspect ratio better --- gfx/rpi.c | 106 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 47 deletions(-) diff --git a/gfx/rpi.c b/gfx/rpi.c index 513fa49062..62c94b335a 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -28,6 +28,8 @@ typedef struct { EGLContext mContext; uint32_t mScreenWidth; uint32_t mScreenHeight; + float mScreenAspect; + bool mKeepAspect; unsigned mTextureWidth; unsigned mTextureHeight; unsigned mRenderWidth; @@ -139,57 +141,17 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v assert(result != EGL_FALSE); rpi->mTexType = video->rgb32 ? VG_sABGR_8888 : VG_sARGB_1555; + rpi->mKeepAspect = video->force_aspect; + + // check for SD televisions: they should always be 4:3 + if (dispman_modeinfo.width == 720 && (dispman_modeinfo.height == 480 || dispman_modeinfo.height == 576)) + rpi->mScreenAspect = 4.0f / 3.0f; + else + rpi->mScreenAspect = (float) dispman_modeinfo.width / dispman_modeinfo.height; VGfloat clearColor[4] = {0, 0, 0, 1}; vgSetfv(VG_CLEAR_COLOR, 4, clearColor); - // set viewport for aspect ratio, taken from RetroArch - if (video->force_aspect) - { - float desired_aspect = g_settings.video.aspect_ratio; - float device_aspect = (float) dispman_modeinfo.width / dispman_modeinfo.height; - - // If the aspect ratios of screen and desired aspect ratio are sufficiently equal (floating point stuff), - // assume they are actually equal. - if (fabs(device_aspect - desired_aspect) < 0.0001) - { - rpi->x1 = 0; - rpi->y1 = 0; - rpi->x2 = rpi->mScreenWidth; - rpi->y2 = rpi->mScreenHeight; - } - else if (device_aspect > desired_aspect) - { - float delta = (desired_aspect / device_aspect - 1.0) / 2.0 + 0.5; - rpi->x1 = rpi->mScreenWidth * (0.5 - delta); - rpi->y1 = 0; - rpi->x2 = 2.0 * rpi->mScreenWidth * delta + rpi->x1; - rpi->y2 = rpi->mScreenHeight + rpi->y1; - } - else - { - float delta = (device_aspect / desired_aspect - 1.0) / 2.0 + 0.5; - rpi->x1 = 0; - rpi->y1 = rpi->mScreenHeight * (0.5 - delta); - rpi->x2 = rpi->mScreenWidth + rpi->x1; - rpi->y2 = 2.0 * rpi->mScreenHeight * delta + rpi->y1; - } - } - else - { - rpi->x1 = 0; - rpi->y1 = 0; - rpi->x2 = rpi->mScreenWidth; - rpi->y2 = rpi->mScreenHeight; - } - - rpi->scissor[0] = rpi->x1; - rpi->scissor[1] = rpi->y1; - rpi->scissor[2] = rpi->x2 - rpi->x1; - rpi->scissor[3] = rpi->y2 - rpi->y1; - - vgSetiv(VG_SCISSOR_RECTS, 4, rpi->scissor); - rpi->mTextureWidth = rpi->mTextureHeight = video->input_scale * RARCH_SCALE_BASE; // We can't use the native format because there's no sXRGB_1555 type and // emulation cores can send 0 in the top bit. We lose some speed on @@ -565,6 +527,55 @@ static void rpi_draw_message(rpi_t *rpi, const char *msg) #endif +static void rpi_calculate_quad(rpi_t *rpi) +{ + // set viewport for aspect ratio, taken from the OpenGL driver + if (rpi->mKeepAspect) + { + float desired_aspect = g_settings.video.aspect_ratio; + + // If the aspect ratios of screen and desired aspect ratio are sufficiently equal (floating point stuff), + // assume they are actually equal. + if (fabs(rpi->mScreenAspect - desired_aspect) < 0.0001) + { + rpi->x1 = 0; + rpi->y1 = 0; + rpi->x2 = rpi->mScreenWidth; + rpi->y2 = rpi->mScreenHeight; + } + else if (rpi->mScreenAspect > desired_aspect) + { + float delta = (desired_aspect / rpi->mScreenAspect - 1.0) / 2.0 + 0.5; + rpi->x1 = rpi->mScreenWidth * (0.5 - delta); + rpi->y1 = 0; + rpi->x2 = 2.0 * rpi->mScreenWidth * delta + rpi->x1; + rpi->y2 = rpi->mScreenHeight + rpi->y1; + } + else + { + float delta = (rpi->mScreenAspect / desired_aspect - 1.0) / 2.0 + 0.5; + rpi->x1 = 0; + rpi->y1 = rpi->mScreenHeight * (0.5 - delta); + rpi->x2 = rpi->mScreenWidth + rpi->x1; + rpi->y2 = 2.0 * rpi->mScreenHeight * delta + rpi->y1; + } + } + else + { + rpi->x1 = 0; + rpi->y1 = 0; + rpi->x2 = rpi->mScreenWidth; + rpi->y2 = rpi->mScreenHeight; + } + + rpi->scissor[0] = rpi->x1; + rpi->scissor[1] = rpi->y1; + rpi->scissor[2] = rpi->x2 - rpi->x1; + rpi->scissor[3] = rpi->y2 - rpi->y1; + + vgSetiv(VG_SCISSOR_RECTS, 4, rpi->scissor); +} + static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) { rpi_t *rpi = (rpi_t*)data; @@ -573,6 +584,7 @@ static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned he { rpi->mRenderWidth = width; rpi->mRenderHeight = height; + rpi_calculate_quad(rpi); vguComputeWarpQuadToQuad( rpi->x1, rpi->y1, rpi->x2, rpi->y1, rpi->x2, rpi->y2, rpi->x1, rpi->y2, // needs to be flipped, Khronos loves their bottom-left origin From 0ca21ef32179816153f230f35d5e41d0d623dac1 Mon Sep 17 00:00:00 2001 From: Toad King Date: Sat, 16 Jun 2012 03:58:21 -0400 Subject: [PATCH 12/21] ignore extended scancodes --- input/linuxraw_input.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/input/linuxraw_input.c b/input/linuxraw_input.c index a1c5af9e53..4ba292043c 100644 --- a/input/linuxraw_input.c +++ b/input/linuxraw_input.c @@ -250,11 +250,17 @@ static void linuxraw_input_poll(void *data) { linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; uint8_t c; + uint16_t t; while (read(0, &c, 1)) { bool pressed = !(c & 0x80); c &= ~0x80; + + // ignore extended scancodes + if (!c) + read(0, &t, 2); + linuxraw->state[c] = pressed; } From f21371f166a49344a7f9f1d90f4c2d78e2389175 Mon Sep 17 00:00:00 2001 From: Toad King Date: Tue, 19 Jun 2012 12:41:06 -0400 Subject: [PATCH 13/21] reuse font code for Raspberry Pi graphics core also move bcm_host_init() to graphics core --- gfx/fonts/fonts.c | 10 +- gfx/fonts/fonts.h | 1 + gfx/rpi.c | 437 ++++++++++++---------------------------------- retroarch.c | 7 - 4 files changed, 121 insertions(+), 334 deletions(-) diff --git a/gfx/fonts/fonts.c b/gfx/fonts/fonts.c index c027a7133f..b6ac68e695 100644 --- a/gfx/fonts/fonts.c +++ b/gfx/fonts/fonts.c @@ -93,8 +93,12 @@ void font_renderer_msg(font_renderer_t *handle, const char *msg, struct font_out tmp->width = slot->bitmap.width; tmp->height = slot->bitmap.rows; tmp->pitch = slot->bitmap.pitch; - tmp->off_x = off_x + slot->bitmap_left; - tmp->off_y = off_y + slot->bitmap_top - slot->bitmap.rows; + tmp->advance_x = slot->advance.x >> 6; + tmp->advance_y = slot->advance.y >> 6; + tmp->char_off_x = slot->bitmap_left; + tmp->char_off_y = slot->bitmap_top - slot->bitmap.rows; + tmp->off_x = off_x + tmp->char_off_x; + tmp->off_y = off_y + tmp->char_off_y; tmp->next = NULL; if (i == 0) @@ -147,6 +151,8 @@ static const char *font_paths[] = { static const char *font_paths[] = { "/usr/share/fonts/TTF/DejaVuSansMono.ttf", "/usr/share/fonts/TTF/DejaVuSans.ttf", + "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf", + "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", #endif "osd-font.ttf", // Magic font to search for, useful for distribution. }; diff --git a/gfx/fonts/fonts.h b/gfx/fonts/fonts.h index 6f2abd6934..f99f94df2c 100644 --- a/gfx/fonts/fonts.h +++ b/gfx/fonts/fonts.h @@ -26,6 +26,7 @@ struct font_output uint8_t *output; // 8-bit intensity. unsigned width, height, pitch; int off_x, off_y; + int advance_x, advance_y, char_off_x, char_off_y; // for advanced font rendering struct font_output *next; // linked list. }; diff --git a/gfx/rpi.c b/gfx/rpi.c index 62c94b335a..bed72cdb99 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -1,3 +1,19 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2012 - Michael Lelli + * + * 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 #include #include @@ -14,10 +30,7 @@ typedef struct linuxraw_input linuxraw_input_t; #include "../driver.h" #ifdef HAVE_FREETYPE -#include -#include -#include FT_FREETYPE_H -#include FT_OUTLINE_H +#include "fonts/fonts.h" #include "../file.h" #endif @@ -43,9 +56,8 @@ typedef struct { #ifdef HAVE_FREETYPE char *mLastMsg; uint32_t mFontHeight; - FT_Library ftLib; - FT_Face ftFace; VGFont mFont; + font_renderer_t *mFontRenderer; bool mFontsOn; VGuint mMsgLength; VGuint mGlyphIndices[1024]; @@ -89,6 +101,8 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v EGLConfig config; + bcm_host_init(); + // get an EGL display connection rpi->mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); assert(rpi->mDisplay != EGL_NO_DISPLAY); @@ -160,87 +174,41 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v rpi->mImage = vgCreateImage(video->rgb32 ? VG_sABGR_8888 : VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, video->smooth ? VG_IMAGE_QUALITY_BETTER : VG_IMAGE_QUALITY_NONANTIALIASED); rpi_set_nonblock_state(rpi, !video->vsync); - if (isatty(0)) + linuxraw_input_t *linuxraw_input = (linuxraw_input_t *)input_linuxraw.init(); + if (linuxraw_input) { - const linuxraw_input_t *linuxraw_input = (const linuxraw_input_t *) input_linuxraw.init(); - if (linuxraw_input) - { - *input = (const input_driver_t *) &input_linuxraw; - *input_data = linuxraw_input; - } + *input = (const input_driver_t *)&input_linuxraw; + *input_data = linuxraw_input; } #ifdef HAVE_FREETYPE - - static const char *font_paths[] = { - "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf", - "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", - "osd-font.ttf", // Magic font to search for, useful for distribution. - }; - - const char *font = g_settings.video.font_path; - - if (!g_settings.video.font_enable) - goto fail; - - if (!path_file_exists(font)) + if (g_settings.video.font_enable) { - font = NULL; + rpi->mFont = vgCreateFont(0); + rpi->mFontHeight = g_settings.video.font_size * (g_settings.video.font_scale ? (float) rpi->mScreenWidth / 1280.0f : 1.0f); - for (int i = 0; i < sizeof(font_paths) / sizeof(font_paths[0]); i++) + const char *path = g_settings.video.font_path; + if (!*path || !path_file_exists(path)) + path = font_renderer_get_default_font(); + + rpi->mFontRenderer = font_renderer_new(path, rpi->mFontHeight); + + if (rpi->mFont != VG_INVALID_HANDLE && rpi->mFontRenderer) { - if (path_file_exists(font_paths[i])) - { - font = font_paths[i]; - break; - } + rpi->mFontsOn = true; + + rpi->mPaintFg = vgCreatePaint(); + rpi->mPaintBg = vgCreatePaint(); + VGfloat paintFg[] = { g_settings.video.msg_color_r, g_settings.video.msg_color_g, g_settings.video.msg_color_b, 1.0f }; + VGfloat paintBg[] = { g_settings.video.msg_color_r / 2.0f, g_settings.video.msg_color_g / 2.0f, g_settings.video.msg_color_b / 2.0f, 0.5f }; + + vgSetParameteri(rpi->mPaintFg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(rpi->mPaintFg, VG_PAINT_COLOR, 4, paintFg); + + vgSetParameteri(rpi->mPaintBg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(rpi->mPaintBg, VG_PAINT_COLOR, 4, paintBg); } } - - if (!font) - { - RARCH_WARN("No font found, messages disabled...\n"); - goto fail; - } - - if (FT_Init_FreeType(&rpi->ftLib)) { - RARCH_WARN("failed to initialize freetype\n"); - goto fail; - } - - if (FT_New_Face(rpi->ftLib, font, 0, &rpi->ftFace)) { - RARCH_WARN("failed to load %s\n", font); - goto fail; - } - - if (FT_Select_Charmap(rpi->ftFace, FT_ENCODING_UNICODE)) { - RARCH_WARN("failed to select an unicode charmap\n"); - goto fail; - } - - uint32_t size = g_settings.video.font_size * (g_settings.video.font_scale ? (float) rpi->mScreenWidth / 1280.0f : 1.0f); - rpi->mFontHeight = size; - - if (FT_Set_Pixel_Sizes(rpi->ftFace, size, size)) - RARCH_WARN("failed to set pixel sizes\n"); - - rpi->mFont = vgCreateFont(0); - - if (rpi->mFont) - rpi->mFontsOn = true; - - rpi->mPaintFg = vgCreatePaint(); - rpi->mPaintBg = vgCreatePaint(); - VGfloat paintFg[] = { g_settings.video.msg_color_r, g_settings.video.msg_color_g, g_settings.video.msg_color_b, 1.0f }; - VGfloat paintBg[] = { g_settings.video.msg_color_r / 2.0f, g_settings.video.msg_color_g / 2.0f, g_settings.video.msg_color_b / 2.0f, 0.5f }; - - vgSetParameteri(rpi->mPaintFg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); - vgSetParameterfv(rpi->mPaintFg, VG_PAINT_COLOR, 4, paintFg); - - vgSetParameteri(rpi->mPaintBg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); - vgSetParameterfv(rpi->mPaintBg, VG_PAINT_COLOR, 4, paintBg); - - fail: #endif return rpi; @@ -252,6 +220,16 @@ static void rpi_free(void *data) vgDestroyImage(rpi->mImage); +#ifdef HAVE_FREETYPE + if (rpi->mFontsOn) + { + vgDestroyFont(rpi->mFont); + font_renderer_free(rpi->mFontRenderer); + vgDestroyPaint(rpi->mPaintFg); + vgDestroyPaint(rpi->mPaintBg); + } +#endif + // Release EGL resources eglMakeCurrent(rpi->mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(rpi->mDisplay, rpi->mSurface); @@ -263,254 +241,62 @@ static void rpi_free(void *data) #ifdef HAVE_FREETYPE -// mostly adapted from example code in Mesa-3d - -static int path_append(VGPath path, VGubyte segment, const FT_Vector **vectors) +static void rpi_render_message(rpi_t *rpi, const char *msg) { - VGfloat coords[6]; - int i, num_vectors; + free(rpi->mLastMsg); + rpi->mLastMsg = strdup(msg); - switch (segment) + if(rpi->mMsgLength) { - case VG_MOVE_TO: - case VG_LINE_TO: - num_vectors = 1; - break; - case VG_QUAD_TO: - num_vectors = 2; - break; - case VG_CUBIC_TO: - num_vectors = 3; - break; - default: - return -1; + while (--rpi->mMsgLength) + vgClearGlyph(rpi->mFont, rpi->mMsgLength); + + vgClearGlyph(rpi->mFont, 0); + } + + struct font_output_list out; + font_renderer_msg(rpi->mFontRenderer, msg, &out); + struct font_output *head = out.head; + + while (head) + { + if (rpi->mMsgLength >= 1024) break; + + VGfloat origin[2], escapement[2]; + VGImage img; + + escapement[0] = (VGfloat) (head->advance_x); + escapement[1] = (VGfloat) (head->advance_y); + origin[0] = (VGfloat) (-head->char_off_x); + origin[1] = (VGfloat) (head->char_off_y); + + img = vgCreateImage(VG_A_8, head->width, head->height, VG_IMAGE_QUALITY_NONANTIALIASED); + + // flip it + for (unsigned i = 0; i < head->height; i++) + vgImageSubData(img, head->output + head->pitch * i, head->pitch, VG_A_8, 0, head->height - i - 1, head->width, 1); + + vgSetGlyphToImage(rpi->mFont, rpi->mMsgLength, img, origin, escapement); + vgDestroyImage(img); + + rpi->mMsgLength++; + head = head->next; } - for (i = 0; i < num_vectors; i++) - { - coords[2 * i + 0] = (float) vectors[i]->x / 64.0f; - coords[2 * i + 1] = (float) vectors[i]->y / 64.0f; - } + font_renderer_free_output(&out); - vgAppendPathData(path, 1, &segment, (const void *) coords); - - return 0; -} - -static int decompose_move_to(const FT_Vector *to, void *user) -{ - VGPath path = (VGPath) (VGuint) user; - - return path_append(path, VG_MOVE_TO, &to); -} - -static int decompose_line_to(const FT_Vector *to, void *user) -{ - VGPath path = (VGPath) (VGuint) user; - - return path_append(path, VG_LINE_TO, &to); -} - -static int decompose_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) -{ - VGPath path = (VGPath) (VGuint) user; - const FT_Vector *vectors[2] = { control, to }; - - return path_append(path, VG_QUAD_TO, vectors); -} - -static int decompose_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) -{ - VGPath path = (VGPath) (VGuint) user; - const FT_Vector *vectors[3] = { control1, control2, to }; - - return path_append(path, VG_CUBIC_TO, vectors); -} - -static VGHandle convert_outline_glyph(rpi_t *rpi) -{ - FT_GlyphSlot glyph = rpi->ftFace->glyph; - FT_Outline_Funcs funcs = { - decompose_move_to, - decompose_line_to, - decompose_conic_to, - decompose_cubic_to, - 0, 0 - }; - - VGHandle path; - - path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, glyph->outline.n_points, VG_PATH_CAPABILITY_ALL); - - if (FT_Outline_Decompose(&glyph->outline, &funcs, (void *) (VGuint) path)) - { - vgDestroyPath(path); - path = VG_INVALID_HANDLE; - } - - return path; -} - -static VGint glyph_string_add_path(rpi_t *rpi, VGPath path, const VGfloat origin[2], VGfloat escapement[2]) -{ - if (rpi->mMsgLength >= 1024) - return -1; - - if (rpi->mFont != VG_INVALID_HANDLE) - { - vgSetGlyphToPath(rpi->mFont, rpi->mMsgLength, path, VG_TRUE, origin, escapement); - return rpi->mMsgLength++; - } - - return -1; -} - -static VGHandle convert_bitmap_glyph(rpi_t *rpi) -{ - FT_GlyphSlot glyph = rpi->ftFace->glyph; - VGImage image; - VGint width, height, stride; - unsigned char *data; - int i, j; - - switch (glyph->bitmap.pixel_mode) - { - case FT_PIXEL_MODE_MONO: - case FT_PIXEL_MODE_GRAY: - break; - default: - return VG_INVALID_HANDLE; - break; - } - - data = glyph->bitmap.buffer; - width = glyph->bitmap.width; - height = glyph->bitmap.rows; - stride = glyph->bitmap.pitch; - - /* mono to gray, and flip if needed */ - if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) - { - data = malloc(width * height); - if (!data) - return VG_INVALID_HANDLE; - - for (i = 0; i < height; i++) - { - unsigned char *dst = &data[width * i]; - const unsigned char *src; - - if (stride > 0) - src = glyph->bitmap.buffer + stride * (height - i - 1); - else - src = glyph->bitmap.buffer - stride * i; - - for (j = 0; j < width; j++) - { - if (src[j / 8] & (1 << (7 - (j % 8)))) - dst[j] = 0xff; - else - dst[j] = 0x0; - } - } - stride = -width; - } - - image = vgCreateImage(VG_A_8, width, height, VG_IMAGE_QUALITY_NONANTIALIASED); - - if (stride < 0) - { - stride = -stride; - vgImageSubData(image, data, stride, VG_A_8, 0, 0, width, height); - } - else - { - /* flip vertically */ - for (i = 0; i < height; i++) - { - const unsigned char *row = data + stride * i; - - vgImageSubData(image, row, stride, VG_A_8, 0, height - i - 1, width, 1); - } - } - - if (data != glyph->bitmap.buffer) - free(data); - - return (VGHandle) image; -} - -static VGint glyph_string_add_image(rpi_t *rpi, VGImage image, const VGfloat origin[2], VGfloat escapement[2]) -{ - if (rpi->mMsgLength >= 1024) - return -1; - - if (rpi->mFont != VG_INVALID_HANDLE) - { - vgSetGlyphToImage(rpi->mFont, rpi->mMsgLength, image, origin, escapement); - return rpi->mMsgLength++; - } - - return -1; + for (unsigned i = 0; i < rpi->mMsgLength; i++) + rpi->mGlyphIndices[i] = i; } static void rpi_draw_message(rpi_t *rpi, const char *msg) { if (!rpi->mLastMsg || strcmp(rpi->mLastMsg, msg)) - { - if (rpi->mLastMsg) - free(rpi->mLastMsg); - - rpi->mLastMsg = strdup(msg); - - if(rpi->mMsgLength) - while (--rpi->mMsgLength) - vgClearGlyph(rpi->mFont, rpi->mMsgLength); - - for (int i = 0; msg[i]; i++) - { - VGfloat origin[2], escapement[2]; - VGHandle handle; - - /* - * if a character appears more than once, it will be loaded and converted - * again... - */ - if (FT_Load_Char(rpi->ftFace, msg[i], FT_LOAD_DEFAULT)) - { - RARCH_WARN("failed to load glyph '%c'\n", msg[i]); - goto fail; - } - - escapement[0] = (VGfloat) rpi->ftFace->glyph->advance.x / 64.0f; - escapement[1] = (VGfloat) rpi->ftFace->glyph->advance.y / 64.0f; - - switch (rpi->ftFace->glyph->format) - { - case FT_GLYPH_FORMAT_OUTLINE: - handle = convert_outline_glyph(rpi); - origin[0] = 0.0f; - origin[1] = 0.0f; - glyph_string_add_path(rpi, (VGPath) handle, origin, escapement); - break; - case FT_GLYPH_FORMAT_BITMAP: - handle = convert_bitmap_glyph(rpi); - origin[0] = (VGfloat) (-rpi->ftFace->glyph->bitmap_left); - origin[1] = (VGfloat) (rpi->ftFace->glyph->bitmap.rows - rpi->ftFace->glyph->bitmap_top); - glyph_string_add_image(rpi, (VGImage) handle, origin, escapement); - break; - default: - break; - } - } - for (int i = 0; i < rpi->mMsgLength; i++) - rpi->mGlyphIndices[i] = i; - } - - fail: + rpi_render_message(rpi, msg); vgSeti(VG_SCISSORING, VG_FALSE); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL); VGfloat origins[] = { rpi->mScreenWidth * g_settings.video.msg_pos_x - 2.0f, rpi->mScreenHeight * g_settings.video.msg_pos_y - 2.0f }; vgSetfv(VG_GLYPH_ORIGIN, 2, origins); @@ -523,6 +309,7 @@ static void rpi_draw_message(rpi_t *rpi, const char *msg) vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE); vgSeti(VG_SCISSORING, VG_TRUE); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL); } #endif @@ -614,14 +401,14 @@ static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned he static bool rpi_alive(void *data) { - (void)data; - return true; + (void)data; + return true; } static bool rpi_focus(void *data) { - (void)data; - return true; + (void)data; + return true; } static void rpi_set_rotation(void *data, unsigned rotation) @@ -631,13 +418,13 @@ static void rpi_set_rotation(void *data, unsigned rotation) } const video_driver_t video_rpi = { - rpi_init, - rpi_frame, - rpi_set_nonblock_state, - rpi_alive, - rpi_focus, - NULL, - rpi_free, - "rpi", - rpi_set_rotation, + rpi_init, + rpi_frame, + rpi_set_nonblock_state, + rpi_alive, + rpi_focus, + NULL, + rpi_free, + "rpi", + rpi_set_rotation, }; diff --git a/retroarch.c b/retroarch.c index b3cb31915c..2062d2803c 100644 --- a/retroarch.c +++ b/retroarch.c @@ -55,10 +55,6 @@ // We want to use -mconsole in Win32, so we need main(). #endif -#ifdef HAVE_RPI -#include -#endif - // To avoid continous switching if we hold the button down, we require that the button must go from pressed, unpressed back to pressed to be able to toggle between then. static void set_fast_forward_button(bool new_button_state, bool new_hold_button_state) { @@ -2628,9 +2624,6 @@ void rarch_main_deinit(void) // Consoles use the higher level API. int main(int argc, char *argv[]) { -#ifdef HAVE_RPI - bcm_host_init(); -#endif int init_ret; if ((init_ret = rarch_main_init(argc, argv))) return init_ret; rarch_init_msg_queue(); From 9a35040fe66a6e7fde3c24960361225522f5ba54 Mon Sep 17 00:00:00 2001 From: Toad King Date: Tue, 19 Jun 2012 12:42:08 -0400 Subject: [PATCH 14/21] try to restore keyboard mode on program crashes use keycode defines instead of numbers --- input/linuxraw_input.c | 229 +++++++++++++++++++++++------------------ input/linuxraw_input.h | 16 +++ 2 files changed, 143 insertions(+), 102 deletions(-) diff --git a/input/linuxraw_input.c b/input/linuxraw_input.c index 4ba292043c..ab36d98d0e 100644 --- a/input/linuxraw_input.c +++ b/input/linuxraw_input.c @@ -1,6 +1,7 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2010-2012 - Hans-Kristian Arntzen - * + * Copyright (C) 2012 - Michael Lelli + * * 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. @@ -16,9 +17,11 @@ #include "../driver.h" #include +#include #include #include #include +#include #include "../general.h" #include "linuxraw_input.h" #include "rarch_sdl_input.h" @@ -34,111 +37,111 @@ struct key_bind static unsigned keysym_lut[SK_LAST]; static const struct key_bind lut_binds[] = { - { 1, SK_ESCAPE }, - { 2, SK_1 }, - { 3, SK_2 }, - { 4, SK_3}, - { 5, SK_4 }, - { 6, SK_5 }, - { 7, SK_6 }, - { 8, SK_7 }, - { 9, SK_8 }, - { 10, SK_9 }, - { 11, SK_0 }, - { 12, SK_MINUS }, - { 13, SK_EQUALS }, - { 14, SK_BACKSPACE }, - { 15, SK_TAB }, - { 16, SK_q }, - { 17, SK_w }, - { 18, SK_e }, - { 19, SK_r }, - { 20, SK_t }, - { 21, SK_y }, - { 22, SK_u }, - { 23, SK_i }, - { 24, SK_o }, - { 25, SK_p }, - { 26, SK_LEFTBRACKET }, - { 27, SK_RIGHTBRACKET }, - { 28, SK_RETURN }, - { 29, SK_LCTRL }, - { 30, SK_a }, - { 31, SK_s }, - { 32, SK_d }, - { 33, SK_f }, - { 34, SK_g }, - { 35, SK_h }, - { 36, SK_j }, - { 37, SK_k }, - { 38, SK_l }, - { 39, SK_SEMICOLON }, - { 40, SK_COMMA }, - { 41, SK_BACKQUOTE }, - { 42, SK_LSHIFT }, - { 43, SK_BACKSLASH }, - { 44, SK_z }, - { 45, SK_x }, - { 46, SK_c }, - { 47, SK_v }, - { 48, SK_b }, - { 49, SK_n }, - { 50, SK_m }, - { 51, SK_COMMA }, - { 52, SK_PERIOD }, - { 53, SK_SLASH }, - { 54, SK_RSHIFT }, - { 55, SK_KP_MULTIPLY }, - { 56, SK_LALT }, - { 57, SK_SPACE }, - { 58, SK_CAPSLOCK }, - { 59, SK_F1 }, - { 60, SK_F2 }, - { 61, SK_F3 }, - { 62, SK_F4 }, - { 63, SK_F5 }, - { 64, SK_F6 }, - { 65, SK_F7 }, - { 66, SK_F8 }, - { 67, SK_F9 }, - { 68, SK_F10 }, - { 69, SK_NUMLOCK }, - { 70, SK_SCROLLOCK }, - { 71, SK_KP7 }, - { 72, SK_KP8 }, - { 73, SK_KP9 }, - { 74, SK_KP_MINUS }, - { 75, SK_KP4 }, - { 76, SK_KP5 }, - { 77, SK_KP6 }, - { 78, SK_KP_PLUS }, - { 79, SK_KP1 }, - { 80, SK_KP2 }, - { 81, SK_KP3 }, - { 82, SK_KP0 }, - { 83, SK_KP_PERIOD }, + { KEY_ESC, SK_ESCAPE }, + { KEY_1, SK_1 }, + { KEY_2, SK_2 }, + { KEY_3, SK_3}, + { KEY_4, SK_4 }, + { KEY_5, SK_5 }, + { KEY_6, SK_6 }, + { KEY_7, SK_7 }, + { KEY_8, SK_8 }, + { KEY_9, SK_9 }, + { KEY_0, SK_0 }, + { KEY_MINUS, SK_MINUS }, + { KEY_EQUAL, SK_EQUALS }, + { KEY_BACKSPACE, SK_BACKSPACE }, + { KEY_TAB, SK_TAB }, + { KEY_Q, SK_q }, + { KEY_W, SK_w }, + { KEY_E, SK_e }, + { KEY_R, SK_r }, + { KEY_T, SK_t }, + { KEY_Y, SK_y }, + { KEY_U, SK_u }, + { KEY_I, SK_i }, + { KEY_O, SK_o }, + { KEY_P, SK_p }, + { KEY_LEFTBRACE, SK_LEFTBRACKET }, + { KEY_RIGHTBRACE, SK_RIGHTBRACKET }, + { KEY_ENTER, SK_RETURN }, + { KEY_LEFTCTRL, SK_LCTRL }, + { KEY_A, SK_a }, + { KEY_S, SK_s }, + { KEY_D, SK_d }, + { KEY_F, SK_f }, + { KEY_G, SK_g }, + { KEY_H, SK_h }, + { KEY_J, SK_j }, + { KEY_K, SK_k }, + { KEY_L, SK_l }, + { KEY_SEMICOLON, SK_SEMICOLON }, + { KEY_APOSTROPHE, SK_QUOTE }, + { KEY_GRAVE, SK_BACKQUOTE }, + { KEY_LEFTSHIFT, SK_LSHIFT }, + { KEY_BACKSLASH, SK_BACKSLASH }, + { KEY_Z, SK_z }, + { KEY_X, SK_x }, + { KEY_C, SK_c }, + { KEY_V, SK_v }, + { KEY_B, SK_b }, + { KEY_N, SK_n }, + { KEY_M, SK_m }, + { KEY_COMMA, SK_COMMA }, + { KEY_DOT, SK_PERIOD }, + { KEY_SLASH, SK_SLASH }, + { KEY_RIGHTSHIFT, SK_RSHIFT }, + { KEY_KPASTERISK, SK_KP_MULTIPLY }, + { KEY_LEFTALT, SK_LALT }, + { KEY_SPACE, SK_SPACE }, + { KEY_CAPSLOCK, SK_CAPSLOCK }, + { KEY_F1, SK_F1 }, + { KEY_F2, SK_F2 }, + { KEY_F3, SK_F3 }, + { KEY_F4, SK_F4 }, + { KEY_F5, SK_F5 }, + { KEY_F6, SK_F6 }, + { KEY_F7, SK_F7 }, + { KEY_F8, SK_F8 }, + { KEY_F9, SK_F9 }, + { KEY_F10, SK_F10 }, + { KEY_NUMLOCK, SK_NUMLOCK }, + { KEY_SCROLLLOCK, SK_SCROLLOCK }, + { KEY_KP7, SK_KP7 }, + { KEY_KP8, SK_KP8 }, + { KEY_KP9, SK_KP9 }, + { KEY_KPMINUS, SK_KP_MINUS }, + { KEY_KP4, SK_KP4 }, + { KEY_KP5, SK_KP5 }, + { KEY_KP6, SK_KP6 }, + { KEY_KPPLUS, SK_KP_PLUS }, + { KEY_KP1, SK_KP1 }, + { KEY_KP2, SK_KP2 }, + { KEY_KP3, SK_KP3 }, + { KEY_KP0, SK_KP0 }, + { KEY_KPDOT, SK_KP_PERIOD }, - { 87, SK_F11 }, - { 88, SK_F12 }, + { KEY_F11, SK_F11 }, + { KEY_F12, SK_F12 }, - { 96, SK_KP_ENTER }, - { 97, SK_RCTRL }, - { 98, SK_KP_DIVIDE }, - { 99, SK_PRINT }, - { 100, SK_RALT }, + { KEY_KPENTER, SK_KP_ENTER }, + { KEY_RIGHTCTRL, SK_RCTRL }, + { KEY_KPSLASH, SK_KP_DIVIDE }, + { KEY_SYSRQ, SK_PRINT }, + { KEY_RIGHTALT, SK_RALT }, - { 102, SK_HOME }, - { 103, SK_UP }, - { 104, SK_PAGEUP }, - { 105, SK_LEFT }, - { 106, SK_RIGHT }, - { 107, SK_END }, - { 108, SK_DOWN }, - { 109, SK_PAGEDOWN }, - { 110, SK_INSERT }, - { 111, SK_DELETE }, + { KEY_HOME, SK_HOME }, + { KEY_UP, SK_UP }, + { KEY_PAGEUP, SK_PAGEUP }, + { KEY_LEFT, SK_LEFT }, + { KEY_RIGHT, SK_RIGHT }, + { KEY_END, SK_END }, + { KEY_DOWN, SK_DOWN }, + { KEY_PAGEDOWN, SK_PAGEDOWN }, + { KEY_INSERT, SK_INSERT }, + { KEY_DELETE, SK_DELETE }, - { 119, SK_PAUSE }, + { KEY_PAUSE, SK_PAUSE }, }; static void init_lut(void) @@ -158,8 +161,19 @@ static void linuxraw_resetKbmd() } } +static void linuxraw_exitGracefully(int sig) +{ + linuxraw_resetKbmd(); + signal(sig, SIG_DFL); + kill(getpid(), sig); +} + static void *linuxraw_input_init(void) { + // only work on terminals + if (!isatty(0)) + return NULL; + linuxraw_input_t *linuxraw = (linuxraw_input_t*)calloc(1, sizeof(*linuxraw)); if (!linuxraw) return NULL; @@ -185,11 +199,22 @@ static void *linuxraw_input_init(void) return NULL; } + // trap some standard termination codes so we can restore the keyboard before we lose control + signal(SIGABRT, linuxraw_exitGracefully); + signal(SIGBUS, linuxraw_exitGracefully); + signal(SIGFPE, linuxraw_exitGracefully); + signal(SIGILL, linuxraw_exitGracefully); + signal(SIGINT, linuxraw_exitGracefully); + signal(SIGQUIT, linuxraw_exitGracefully); + signal(SIGSEGV, linuxraw_exitGracefully); + signal(SIGTERM, linuxraw_exitGracefully); + atexit(linuxraw_resetKbmd); linuxraw->sdl = (sdl_input_t*)input_sdl.init(); if (!linuxraw->sdl) { + linuxraw_resetKbmd(); free(linuxraw); return NULL; } diff --git a/input/linuxraw_input.h b/input/linuxraw_input.h index a75caf03bb..5ad9c2c95f 100644 --- a/input/linuxraw_input.h +++ b/input/linuxraw_input.h @@ -1,3 +1,19 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2012 - Michael Lelli + * + * 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 "../general.h" #include "rarch_sdl_input.h" From 8e360138d3938a2b07f66ea5706e177f14824c55 Mon Sep 17 00:00:00 2001 From: Toad King Date: Tue, 19 Jun 2012 12:42:32 -0400 Subject: [PATCH 15/21] detect Raspberry Pi through bcm_host library --- qb/config.libs.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/qb/config.libs.sh b/qb/config.libs.sh index dfc724f720..57afad9eac 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -10,15 +10,15 @@ add_define_make NOUNUSED "$HAVE_NOUNUSED" if [ "$OS" = 'BSD' ]; then DYLIB=-lc; else DYLIB=-ldl; fi -if [ -d /opt/vc/lib ]; then - add_library_dirs /opt/vc/lib - add_include_dirs /opt/vc/include - add_include_dirs /opt/vc/include/interface/vcos/pthreads +[ -d /opt/vc/lib ] && add_library_dirs /opt/vc/lib +check_lib RPI -lbcm_host bcm_host_init + +if [ "$HAVE_RPI" = 'yes' ]; then + [ -d /opt/vc/include ] && add_include_dirs /opt/vc/include + [ -d /opt/vc/include/interface/vcos/pthreads ] && add_include_dirs /opt/vc/include/interface/vcos/pthreads + # the gles library gets messed up with the gl library if available, so turn it off - HAVE_OPENGL=no - HAVE_RPI=yes -else - HAVE_RPI=no + HAVE_OPENGL='no' fi if [ "$LIBRETRO" ]; then From 55b72676946456e710770abd905b8b61adaf07df Mon Sep 17 00:00:00 2001 From: Toad King Date: Tue, 19 Jun 2012 12:44:10 -0400 Subject: [PATCH 16/21] tabs -> 3 spaces --- gfx/rpi.c | 554 ++++++++++++++++++++--------------------- input/linuxraw_input.c | 402 +++++++++++++++--------------- input/linuxraw_input.h | 4 +- 3 files changed, 480 insertions(+), 480 deletions(-) diff --git a/gfx/rpi.c b/gfx/rpi.c index bed72cdb99..f90538e95c 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -36,395 +36,395 @@ typedef struct linuxraw_input linuxraw_input_t; typedef struct { - EGLDisplay mDisplay; - EGLSurface mSurface; - EGLContext mContext; - uint32_t mScreenWidth; - uint32_t mScreenHeight; - float mScreenAspect; - bool mKeepAspect; - unsigned mTextureWidth; - unsigned mTextureHeight; - unsigned mRenderWidth; - unsigned mRenderHeight; - unsigned x1, y1, x2, y2; - VGImageFormat mTexType; - VGImage mImage; - VGfloat mTransformMatrix[9]; - VGint scissor[4]; + EGLDisplay mDisplay; + EGLSurface mSurface; + EGLContext mContext; + uint32_t mScreenWidth; + uint32_t mScreenHeight; + float mScreenAspect; + bool mKeepAspect; + unsigned mTextureWidth; + unsigned mTextureHeight; + unsigned mRenderWidth; + unsigned mRenderHeight; + unsigned x1, y1, x2, y2; + VGImageFormat mTexType; + VGImage mImage; + VGfloat mTransformMatrix[9]; + VGint scissor[4]; #ifdef HAVE_FREETYPE - char *mLastMsg; - uint32_t mFontHeight; - VGFont mFont; - font_renderer_t *mFontRenderer; - bool mFontsOn; - VGuint mMsgLength; - VGuint mGlyphIndices[1024]; - VGPaint mPaintFg; - VGPaint mPaintBg; + char *mLastMsg; + uint32_t mFontHeight; + VGFont mFont; + font_renderer_t *mFontRenderer; + bool mFontsOn; + VGuint mMsgLength; + VGuint mGlyphIndices[1024]; + VGPaint mPaintFg; + VGPaint mPaintBg; #endif } rpi_t; static void rpi_set_nonblock_state(void *data, bool state) { - rpi_t *rpi = (rpi_t*)data; - eglSwapInterval(rpi->mDisplay, state ? 0 : 1); + rpi_t *rpi = (rpi_t*)data; + eglSwapInterval(rpi->mDisplay, state ? 0 : 1); } static void *rpi_init(const video_info_t *video, const input_driver_t **input, void **input_data) { - int32_t success; - EGLBoolean result; - EGLint num_config; - rpi_t *rpi = (rpi_t*)calloc(1, sizeof(rpi_t)); - *input = NULL; + int32_t success; + EGLBoolean result; + EGLint num_config; + rpi_t *rpi = (rpi_t*)calloc(1, sizeof(rpi_t)); + *input = NULL; - static EGL_DISPMANX_WINDOW_T nativewindow; + static EGL_DISPMANX_WINDOW_T nativewindow; - DISPMANX_ELEMENT_HANDLE_T dispman_element; - DISPMANX_DISPLAY_HANDLE_T dispman_display; - DISPMANX_UPDATE_HANDLE_T dispman_update; - DISPMANX_MODEINFO_T dispman_modeinfo; - VC_RECT_T dst_rect; - VC_RECT_T src_rect; + DISPMANX_ELEMENT_HANDLE_T dispman_element; + DISPMANX_DISPLAY_HANDLE_T dispman_display; + DISPMANX_UPDATE_HANDLE_T dispman_update; + DISPMANX_MODEINFO_T dispman_modeinfo; + VC_RECT_T dst_rect; + VC_RECT_T src_rect; - static const EGLint attribute_list[] = - { - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_NONE - }; + static const EGLint attribute_list[] = + { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_NONE + }; - EGLConfig config; + EGLConfig config; - bcm_host_init(); + bcm_host_init(); - // get an EGL display connection - rpi->mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - assert(rpi->mDisplay != EGL_NO_DISPLAY); + // get an EGL display connection + rpi->mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + assert(rpi->mDisplay != EGL_NO_DISPLAY); - // initialize the EGL display connection - result = eglInitialize(rpi->mDisplay, NULL, NULL); - assert(result != EGL_FALSE); - eglBindAPI(EGL_OPENVG_API); + // initialize the EGL display connection + result = eglInitialize(rpi->mDisplay, NULL, NULL); + assert(result != EGL_FALSE); + eglBindAPI(EGL_OPENVG_API); - // get an appropriate EGL frame buffer configuration - result = eglChooseConfig(rpi->mDisplay, attribute_list, &config, 1, &num_config); - assert(result != EGL_FALSE); + // get an appropriate EGL frame buffer configuration + result = eglChooseConfig(rpi->mDisplay, attribute_list, &config, 1, &num_config); + assert(result != EGL_FALSE); - // create an EGL rendering context - rpi->mContext = eglCreateContext(rpi->mDisplay, config, EGL_NO_CONTEXT, NULL); - assert(rpi->mContext != EGL_NO_CONTEXT); + // create an EGL rendering context + rpi->mContext = eglCreateContext(rpi->mDisplay, config, EGL_NO_CONTEXT, NULL); + assert(rpi->mContext != EGL_NO_CONTEXT); - // create an EGL window surface - success = graphics_get_display_size(0 /* LCD */, &rpi->mScreenWidth, &rpi->mScreenHeight); - assert(success >= 0); + // create an EGL window surface + success = graphics_get_display_size(0 /* LCD */, &rpi->mScreenWidth, &rpi->mScreenHeight); + assert(success >= 0); - dst_rect.x = 0; - dst_rect.y = 0; - dst_rect.width = rpi->mScreenWidth; - dst_rect.height = rpi->mScreenHeight; + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.width = rpi->mScreenWidth; + dst_rect.height = rpi->mScreenHeight; - src_rect.x = 0; - src_rect.y = 0; - src_rect.width = rpi->mScreenWidth << 16; - src_rect.height = rpi->mScreenHeight << 16; + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = rpi->mScreenWidth << 16; + src_rect.height = rpi->mScreenHeight << 16; - dispman_display = vc_dispmanx_display_open(0 /* LCD */); - vc_dispmanx_display_get_info(dispman_display, &dispman_modeinfo); - dispman_update = vc_dispmanx_update_start(0); + dispman_display = vc_dispmanx_display_open(0 /* LCD */); + vc_dispmanx_display_get_info(dispman_display, &dispman_modeinfo); + dispman_update = vc_dispmanx_update_start(0); - dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display, - 0/*layer*/, &dst_rect, 0/*src*/, - &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, DISPMANX_NO_ROTATE); + dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display, + 0/*layer*/, &dst_rect, 0/*src*/, + &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, DISPMANX_NO_ROTATE); - nativewindow.element = dispman_element; - nativewindow.width = rpi->mScreenWidth; - nativewindow.height = rpi->mScreenHeight; - vc_dispmanx_update_submit_sync(dispman_update); + nativewindow.element = dispman_element; + nativewindow.width = rpi->mScreenWidth; + nativewindow.height = rpi->mScreenHeight; + vc_dispmanx_update_submit_sync(dispman_update); - rpi->mSurface = eglCreateWindowSurface(rpi->mDisplay, config, &nativewindow, NULL); - assert(rpi->mSurface != EGL_NO_SURFACE); + rpi->mSurface = eglCreateWindowSurface(rpi->mDisplay, config, &nativewindow, NULL); + assert(rpi->mSurface != EGL_NO_SURFACE); - // connect the context to the surface - result = eglMakeCurrent(rpi->mDisplay, rpi->mSurface, rpi->mSurface, rpi->mContext); - assert(result != EGL_FALSE); + // connect the context to the surface + result = eglMakeCurrent(rpi->mDisplay, rpi->mSurface, rpi->mSurface, rpi->mContext); + assert(result != EGL_FALSE); - rpi->mTexType = video->rgb32 ? VG_sABGR_8888 : VG_sARGB_1555; - rpi->mKeepAspect = video->force_aspect; + rpi->mTexType = video->rgb32 ? VG_sABGR_8888 : VG_sARGB_1555; + rpi->mKeepAspect = video->force_aspect; - // check for SD televisions: they should always be 4:3 - if (dispman_modeinfo.width == 720 && (dispman_modeinfo.height == 480 || dispman_modeinfo.height == 576)) - rpi->mScreenAspect = 4.0f / 3.0f; - else - rpi->mScreenAspect = (float) dispman_modeinfo.width / dispman_modeinfo.height; + // check for SD televisions: they should always be 4:3 + if (dispman_modeinfo.width == 720 && (dispman_modeinfo.height == 480 || dispman_modeinfo.height == 576)) + rpi->mScreenAspect = 4.0f / 3.0f; + else + rpi->mScreenAspect = (float) dispman_modeinfo.width / dispman_modeinfo.height; - VGfloat clearColor[4] = {0, 0, 0, 1}; - vgSetfv(VG_CLEAR_COLOR, 4, clearColor); + VGfloat clearColor[4] = {0, 0, 0, 1}; + vgSetfv(VG_CLEAR_COLOR, 4, clearColor); - rpi->mTextureWidth = rpi->mTextureHeight = video->input_scale * RARCH_SCALE_BASE; - // We can't use the native format because there's no sXRGB_1555 type and - // emulation cores can send 0 in the top bit. We lose some speed on - // conversion but I doubt it has any real affect, since we are only drawing - // one image at the end of the day. Still keep the alpha channel for ABGR. - rpi->mImage = vgCreateImage(video->rgb32 ? VG_sABGR_8888 : VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, video->smooth ? VG_IMAGE_QUALITY_BETTER : VG_IMAGE_QUALITY_NONANTIALIASED); - rpi_set_nonblock_state(rpi, !video->vsync); + rpi->mTextureWidth = rpi->mTextureHeight = video->input_scale * RARCH_SCALE_BASE; + // We can't use the native format because there's no sXRGB_1555 type and + // emulation cores can send 0 in the top bit. We lose some speed on + // conversion but I doubt it has any real affect, since we are only drawing + // one image at the end of the day. Still keep the alpha channel for ABGR. + rpi->mImage = vgCreateImage(video->rgb32 ? VG_sABGR_8888 : VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, video->smooth ? VG_IMAGE_QUALITY_BETTER : VG_IMAGE_QUALITY_NONANTIALIASED); + rpi_set_nonblock_state(rpi, !video->vsync); - linuxraw_input_t *linuxraw_input = (linuxraw_input_t *)input_linuxraw.init(); - if (linuxraw_input) - { - *input = (const input_driver_t *)&input_linuxraw; - *input_data = linuxraw_input; - } + linuxraw_input_t *linuxraw_input = (linuxraw_input_t *)input_linuxraw.init(); + if (linuxraw_input) + { + *input = (const input_driver_t *)&input_linuxraw; + *input_data = linuxraw_input; + } #ifdef HAVE_FREETYPE - if (g_settings.video.font_enable) - { - rpi->mFont = vgCreateFont(0); - rpi->mFontHeight = g_settings.video.font_size * (g_settings.video.font_scale ? (float) rpi->mScreenWidth / 1280.0f : 1.0f); + if (g_settings.video.font_enable) + { + rpi->mFont = vgCreateFont(0); + rpi->mFontHeight = g_settings.video.font_size * (g_settings.video.font_scale ? (float) rpi->mScreenWidth / 1280.0f : 1.0f); - const char *path = g_settings.video.font_path; - if (!*path || !path_file_exists(path)) - path = font_renderer_get_default_font(); + const char *path = g_settings.video.font_path; + if (!*path || !path_file_exists(path)) + path = font_renderer_get_default_font(); - rpi->mFontRenderer = font_renderer_new(path, rpi->mFontHeight); + rpi->mFontRenderer = font_renderer_new(path, rpi->mFontHeight); - if (rpi->mFont != VG_INVALID_HANDLE && rpi->mFontRenderer) - { - rpi->mFontsOn = true; + if (rpi->mFont != VG_INVALID_HANDLE && rpi->mFontRenderer) + { + rpi->mFontsOn = true; - rpi->mPaintFg = vgCreatePaint(); - rpi->mPaintBg = vgCreatePaint(); - VGfloat paintFg[] = { g_settings.video.msg_color_r, g_settings.video.msg_color_g, g_settings.video.msg_color_b, 1.0f }; - VGfloat paintBg[] = { g_settings.video.msg_color_r / 2.0f, g_settings.video.msg_color_g / 2.0f, g_settings.video.msg_color_b / 2.0f, 0.5f }; + rpi->mPaintFg = vgCreatePaint(); + rpi->mPaintBg = vgCreatePaint(); + VGfloat paintFg[] = { g_settings.video.msg_color_r, g_settings.video.msg_color_g, g_settings.video.msg_color_b, 1.0f }; + VGfloat paintBg[] = { g_settings.video.msg_color_r / 2.0f, g_settings.video.msg_color_g / 2.0f, g_settings.video.msg_color_b / 2.0f, 0.5f }; - vgSetParameteri(rpi->mPaintFg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); - vgSetParameterfv(rpi->mPaintFg, VG_PAINT_COLOR, 4, paintFg); + vgSetParameteri(rpi->mPaintFg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(rpi->mPaintFg, VG_PAINT_COLOR, 4, paintFg); - vgSetParameteri(rpi->mPaintBg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); - vgSetParameterfv(rpi->mPaintBg, VG_PAINT_COLOR, 4, paintBg); - } - } + vgSetParameteri(rpi->mPaintBg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(rpi->mPaintBg, VG_PAINT_COLOR, 4, paintBg); + } + } #endif - return rpi; + return rpi; } static void rpi_free(void *data) { - rpi_t *rpi = (rpi_t*)data; + rpi_t *rpi = (rpi_t*)data; - vgDestroyImage(rpi->mImage); + vgDestroyImage(rpi->mImage); #ifdef HAVE_FREETYPE - if (rpi->mFontsOn) - { - vgDestroyFont(rpi->mFont); - font_renderer_free(rpi->mFontRenderer); - vgDestroyPaint(rpi->mPaintFg); - vgDestroyPaint(rpi->mPaintBg); - } + if (rpi->mFontsOn) + { + vgDestroyFont(rpi->mFont); + font_renderer_free(rpi->mFontRenderer); + vgDestroyPaint(rpi->mPaintFg); + vgDestroyPaint(rpi->mPaintBg); + } #endif - // Release EGL resources - eglMakeCurrent(rpi->mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroySurface(rpi->mDisplay, rpi->mSurface); - eglDestroyContext(rpi->mDisplay, rpi->mContext); - eglTerminate(rpi->mDisplay); + // Release EGL resources + eglMakeCurrent(rpi->mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(rpi->mDisplay, rpi->mSurface); + eglDestroyContext(rpi->mDisplay, rpi->mContext); + eglTerminate(rpi->mDisplay); - free(rpi); + free(rpi); } #ifdef HAVE_FREETYPE static void rpi_render_message(rpi_t *rpi, const char *msg) { - free(rpi->mLastMsg); - rpi->mLastMsg = strdup(msg); + free(rpi->mLastMsg); + rpi->mLastMsg = strdup(msg); - if(rpi->mMsgLength) - { - while (--rpi->mMsgLength) - vgClearGlyph(rpi->mFont, rpi->mMsgLength); + if(rpi->mMsgLength) + { + while (--rpi->mMsgLength) + vgClearGlyph(rpi->mFont, rpi->mMsgLength); - vgClearGlyph(rpi->mFont, 0); - } + vgClearGlyph(rpi->mFont, 0); + } - struct font_output_list out; - font_renderer_msg(rpi->mFontRenderer, msg, &out); - struct font_output *head = out.head; + struct font_output_list out; + font_renderer_msg(rpi->mFontRenderer, msg, &out); + struct font_output *head = out.head; - while (head) - { - if (rpi->mMsgLength >= 1024) - break; + while (head) + { + if (rpi->mMsgLength >= 1024) + break; - VGfloat origin[2], escapement[2]; - VGImage img; + VGfloat origin[2], escapement[2]; + VGImage img; - escapement[0] = (VGfloat) (head->advance_x); - escapement[1] = (VGfloat) (head->advance_y); - origin[0] = (VGfloat) (-head->char_off_x); - origin[1] = (VGfloat) (head->char_off_y); + escapement[0] = (VGfloat) (head->advance_x); + escapement[1] = (VGfloat) (head->advance_y); + origin[0] = (VGfloat) (-head->char_off_x); + origin[1] = (VGfloat) (head->char_off_y); - img = vgCreateImage(VG_A_8, head->width, head->height, VG_IMAGE_QUALITY_NONANTIALIASED); + img = vgCreateImage(VG_A_8, head->width, head->height, VG_IMAGE_QUALITY_NONANTIALIASED); - // flip it - for (unsigned i = 0; i < head->height; i++) - vgImageSubData(img, head->output + head->pitch * i, head->pitch, VG_A_8, 0, head->height - i - 1, head->width, 1); + // flip it + for (unsigned i = 0; i < head->height; i++) + vgImageSubData(img, head->output + head->pitch * i, head->pitch, VG_A_8, 0, head->height - i - 1, head->width, 1); - vgSetGlyphToImage(rpi->mFont, rpi->mMsgLength, img, origin, escapement); - vgDestroyImage(img); + vgSetGlyphToImage(rpi->mFont, rpi->mMsgLength, img, origin, escapement); + vgDestroyImage(img); - rpi->mMsgLength++; - head = head->next; - } + rpi->mMsgLength++; + head = head->next; + } - font_renderer_free_output(&out); + font_renderer_free_output(&out); - for (unsigned i = 0; i < rpi->mMsgLength; i++) - rpi->mGlyphIndices[i] = i; + for (unsigned i = 0; i < rpi->mMsgLength; i++) + rpi->mGlyphIndices[i] = i; } static void rpi_draw_message(rpi_t *rpi, const char *msg) { - if (!rpi->mLastMsg || strcmp(rpi->mLastMsg, msg)) - rpi_render_message(rpi, msg); + if (!rpi->mLastMsg || strcmp(rpi->mLastMsg, msg)) + rpi_render_message(rpi, msg); - vgSeti(VG_SCISSORING, VG_FALSE); - vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL); + vgSeti(VG_SCISSORING, VG_FALSE); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL); - VGfloat origins[] = { rpi->mScreenWidth * g_settings.video.msg_pos_x - 2.0f, rpi->mScreenHeight * g_settings.video.msg_pos_y - 2.0f }; - vgSetfv(VG_GLYPH_ORIGIN, 2, origins); - vgSetPaint(rpi->mPaintBg, VG_FILL_PATH); - vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE); - origins[0] += 2.0f; - origins[1] += 2.0f; - vgSetfv(VG_GLYPH_ORIGIN, 2, origins); - vgSetPaint(rpi->mPaintFg, VG_FILL_PATH); - vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE); + VGfloat origins[] = { rpi->mScreenWidth * g_settings.video.msg_pos_x - 2.0f, rpi->mScreenHeight * g_settings.video.msg_pos_y - 2.0f }; + vgSetfv(VG_GLYPH_ORIGIN, 2, origins); + vgSetPaint(rpi->mPaintBg, VG_FILL_PATH); + vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE); + origins[0] += 2.0f; + origins[1] += 2.0f; + vgSetfv(VG_GLYPH_ORIGIN, 2, origins); + vgSetPaint(rpi->mPaintFg, VG_FILL_PATH); + vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE); - vgSeti(VG_SCISSORING, VG_TRUE); - vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL); + vgSeti(VG_SCISSORING, VG_TRUE); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL); } #endif static void rpi_calculate_quad(rpi_t *rpi) { - // set viewport for aspect ratio, taken from the OpenGL driver - if (rpi->mKeepAspect) - { - float desired_aspect = g_settings.video.aspect_ratio; + // set viewport for aspect ratio, taken from the OpenGL driver + if (rpi->mKeepAspect) + { + float desired_aspect = g_settings.video.aspect_ratio; - // If the aspect ratios of screen and desired aspect ratio are sufficiently equal (floating point stuff), - // assume they are actually equal. - if (fabs(rpi->mScreenAspect - desired_aspect) < 0.0001) - { - rpi->x1 = 0; - rpi->y1 = 0; - rpi->x2 = rpi->mScreenWidth; - rpi->y2 = rpi->mScreenHeight; - } - else if (rpi->mScreenAspect > desired_aspect) - { - float delta = (desired_aspect / rpi->mScreenAspect - 1.0) / 2.0 + 0.5; - rpi->x1 = rpi->mScreenWidth * (0.5 - delta); - rpi->y1 = 0; - rpi->x2 = 2.0 * rpi->mScreenWidth * delta + rpi->x1; - rpi->y2 = rpi->mScreenHeight + rpi->y1; - } - else - { - float delta = (rpi->mScreenAspect / desired_aspect - 1.0) / 2.0 + 0.5; - rpi->x1 = 0; - rpi->y1 = rpi->mScreenHeight * (0.5 - delta); - rpi->x2 = rpi->mScreenWidth + rpi->x1; - rpi->y2 = 2.0 * rpi->mScreenHeight * delta + rpi->y1; - } - } - else - { - rpi->x1 = 0; - rpi->y1 = 0; - rpi->x2 = rpi->mScreenWidth; - rpi->y2 = rpi->mScreenHeight; - } + // If the aspect ratios of screen and desired aspect ratio are sufficiently equal (floating point stuff), + // assume they are actually equal. + if (fabs(rpi->mScreenAspect - desired_aspect) < 0.0001) + { + rpi->x1 = 0; + rpi->y1 = 0; + rpi->x2 = rpi->mScreenWidth; + rpi->y2 = rpi->mScreenHeight; + } + else if (rpi->mScreenAspect > desired_aspect) + { + float delta = (desired_aspect / rpi->mScreenAspect - 1.0) / 2.0 + 0.5; + rpi->x1 = rpi->mScreenWidth * (0.5 - delta); + rpi->y1 = 0; + rpi->x2 = 2.0 * rpi->mScreenWidth * delta + rpi->x1; + rpi->y2 = rpi->mScreenHeight + rpi->y1; + } + else + { + float delta = (rpi->mScreenAspect / desired_aspect - 1.0) / 2.0 + 0.5; + rpi->x1 = 0; + rpi->y1 = rpi->mScreenHeight * (0.5 - delta); + rpi->x2 = rpi->mScreenWidth + rpi->x1; + rpi->y2 = 2.0 * rpi->mScreenHeight * delta + rpi->y1; + } + } + else + { + rpi->x1 = 0; + rpi->y1 = 0; + rpi->x2 = rpi->mScreenWidth; + rpi->y2 = rpi->mScreenHeight; + } - rpi->scissor[0] = rpi->x1; - rpi->scissor[1] = rpi->y1; - rpi->scissor[2] = rpi->x2 - rpi->x1; - rpi->scissor[3] = rpi->y2 - rpi->y1; + rpi->scissor[0] = rpi->x1; + rpi->scissor[1] = rpi->y1; + rpi->scissor[2] = rpi->x2 - rpi->x1; + rpi->scissor[3] = rpi->y2 - rpi->y1; - vgSetiv(VG_SCISSOR_RECTS, 4, rpi->scissor); + vgSetiv(VG_SCISSOR_RECTS, 4, rpi->scissor); } static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) { - rpi_t *rpi = (rpi_t*)data; + rpi_t *rpi = (rpi_t*)data; - if (width != rpi->mRenderWidth || height != rpi->mRenderHeight) - { - rpi->mRenderWidth = width; - rpi->mRenderHeight = height; - rpi_calculate_quad(rpi); - vguComputeWarpQuadToQuad( - rpi->x1, rpi->y1, rpi->x2, rpi->y1, rpi->x2, rpi->y2, rpi->x1, rpi->y2, - // needs to be flipped, Khronos loves their bottom-left origin - 0, height, width, height, width, 0, 0, 0, - rpi->mTransformMatrix); - vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); - vgLoadMatrix(rpi->mTransformMatrix); - } - vgSeti(VG_SCISSORING, VG_FALSE); - vgClear(0, 0, rpi->mScreenWidth, rpi->mScreenHeight); - vgSeti(VG_SCISSORING, VG_TRUE); + if (width != rpi->mRenderWidth || height != rpi->mRenderHeight) + { + rpi->mRenderWidth = width; + rpi->mRenderHeight = height; + rpi_calculate_quad(rpi); + vguComputeWarpQuadToQuad( + rpi->x1, rpi->y1, rpi->x2, rpi->y1, rpi->x2, rpi->y2, rpi->x1, rpi->y2, + // needs to be flipped, Khronos loves their bottom-left origin + 0, height, width, height, width, 0, 0, 0, + rpi->mTransformMatrix); + vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); + vgLoadMatrix(rpi->mTransformMatrix); + } + vgSeti(VG_SCISSORING, VG_FALSE); + vgClear(0, 0, rpi->mScreenWidth, rpi->mScreenHeight); + vgSeti(VG_SCISSORING, VG_TRUE); - vgImageSubData(rpi->mImage, frame, pitch, rpi->mTexType, 0, 0, width, height); - vgDrawImage(rpi->mImage); + vgImageSubData(rpi->mImage, frame, pitch, rpi->mTexType, 0, 0, width, height); + vgDrawImage(rpi->mImage); #ifdef HAVE_FREETYPE - if (msg && rpi->mFontsOn) - rpi_draw_message(rpi, msg); + if (msg && rpi->mFontsOn) + rpi_draw_message(rpi, msg); #else - (void)msg; + (void)msg; #endif - eglSwapBuffers(rpi->mDisplay, rpi->mSurface); + eglSwapBuffers(rpi->mDisplay, rpi->mSurface); - return true; + return true; } static bool rpi_alive(void *data) { - (void)data; - return true; + (void)data; + return true; } static bool rpi_focus(void *data) { - (void)data; - return true; + (void)data; + return true; } static void rpi_set_rotation(void *data, unsigned rotation) { - (void)data; - (void)rotation; + (void)data; + (void)rotation; } const video_driver_t video_rpi = { - rpi_init, - rpi_frame, - rpi_set_nonblock_state, - rpi_alive, - rpi_focus, - NULL, - rpi_free, - "rpi", - rpi_set_rotation, + rpi_init, + rpi_frame, + rpi_set_nonblock_state, + rpi_alive, + rpi_focus, + NULL, + rpi_free, + "rpi", + rpi_set_rotation, }; diff --git a/input/linuxraw_input.c b/input/linuxraw_input.c index ab36d98d0e..c96eb52616 100644 --- a/input/linuxraw_input.c +++ b/input/linuxraw_input.c @@ -31,272 +31,272 @@ static struct termios oldTerm, newTerm; struct key_bind { - uint8_t x; - enum rarch_key sk; + uint8_t x; + enum rarch_key sk; }; static unsigned keysym_lut[SK_LAST]; static const struct key_bind lut_binds[] = { - { KEY_ESC, SK_ESCAPE }, - { KEY_1, SK_1 }, - { KEY_2, SK_2 }, - { KEY_3, SK_3}, - { KEY_4, SK_4 }, - { KEY_5, SK_5 }, - { KEY_6, SK_6 }, - { KEY_7, SK_7 }, - { KEY_8, SK_8 }, - { KEY_9, SK_9 }, - { KEY_0, SK_0 }, - { KEY_MINUS, SK_MINUS }, - { KEY_EQUAL, SK_EQUALS }, - { KEY_BACKSPACE, SK_BACKSPACE }, - { KEY_TAB, SK_TAB }, - { KEY_Q, SK_q }, - { KEY_W, SK_w }, - { KEY_E, SK_e }, - { KEY_R, SK_r }, - { KEY_T, SK_t }, - { KEY_Y, SK_y }, - { KEY_U, SK_u }, - { KEY_I, SK_i }, - { KEY_O, SK_o }, - { KEY_P, SK_p }, - { KEY_LEFTBRACE, SK_LEFTBRACKET }, - { KEY_RIGHTBRACE, SK_RIGHTBRACKET }, - { KEY_ENTER, SK_RETURN }, - { KEY_LEFTCTRL, SK_LCTRL }, - { KEY_A, SK_a }, - { KEY_S, SK_s }, - { KEY_D, SK_d }, - { KEY_F, SK_f }, - { KEY_G, SK_g }, - { KEY_H, SK_h }, - { KEY_J, SK_j }, - { KEY_K, SK_k }, - { KEY_L, SK_l }, - { KEY_SEMICOLON, SK_SEMICOLON }, - { KEY_APOSTROPHE, SK_QUOTE }, - { KEY_GRAVE, SK_BACKQUOTE }, - { KEY_LEFTSHIFT, SK_LSHIFT }, - { KEY_BACKSLASH, SK_BACKSLASH }, - { KEY_Z, SK_z }, - { KEY_X, SK_x }, - { KEY_C, SK_c }, - { KEY_V, SK_v }, - { KEY_B, SK_b }, - { KEY_N, SK_n }, - { KEY_M, SK_m }, - { KEY_COMMA, SK_COMMA }, - { KEY_DOT, SK_PERIOD }, - { KEY_SLASH, SK_SLASH }, - { KEY_RIGHTSHIFT, SK_RSHIFT }, - { KEY_KPASTERISK, SK_KP_MULTIPLY }, - { KEY_LEFTALT, SK_LALT }, - { KEY_SPACE, SK_SPACE }, - { KEY_CAPSLOCK, SK_CAPSLOCK }, - { KEY_F1, SK_F1 }, - { KEY_F2, SK_F2 }, - { KEY_F3, SK_F3 }, - { KEY_F4, SK_F4 }, - { KEY_F5, SK_F5 }, - { KEY_F6, SK_F6 }, - { KEY_F7, SK_F7 }, - { KEY_F8, SK_F8 }, - { KEY_F9, SK_F9 }, - { KEY_F10, SK_F10 }, - { KEY_NUMLOCK, SK_NUMLOCK }, - { KEY_SCROLLLOCK, SK_SCROLLOCK }, - { KEY_KP7, SK_KP7 }, - { KEY_KP8, SK_KP8 }, - { KEY_KP9, SK_KP9 }, - { KEY_KPMINUS, SK_KP_MINUS }, - { KEY_KP4, SK_KP4 }, - { KEY_KP5, SK_KP5 }, - { KEY_KP6, SK_KP6 }, - { KEY_KPPLUS, SK_KP_PLUS }, - { KEY_KP1, SK_KP1 }, - { KEY_KP2, SK_KP2 }, - { KEY_KP3, SK_KP3 }, - { KEY_KP0, SK_KP0 }, - { KEY_KPDOT, SK_KP_PERIOD }, + { KEY_ESC, SK_ESCAPE }, + { KEY_1, SK_1 }, + { KEY_2, SK_2 }, + { KEY_3, SK_3}, + { KEY_4, SK_4 }, + { KEY_5, SK_5 }, + { KEY_6, SK_6 }, + { KEY_7, SK_7 }, + { KEY_8, SK_8 }, + { KEY_9, SK_9 }, + { KEY_0, SK_0 }, + { KEY_MINUS, SK_MINUS }, + { KEY_EQUAL, SK_EQUALS }, + { KEY_BACKSPACE, SK_BACKSPACE }, + { KEY_TAB, SK_TAB }, + { KEY_Q, SK_q }, + { KEY_W, SK_w }, + { KEY_E, SK_e }, + { KEY_R, SK_r }, + { KEY_T, SK_t }, + { KEY_Y, SK_y }, + { KEY_U, SK_u }, + { KEY_I, SK_i }, + { KEY_O, SK_o }, + { KEY_P, SK_p }, + { KEY_LEFTBRACE, SK_LEFTBRACKET }, + { KEY_RIGHTBRACE, SK_RIGHTBRACKET }, + { KEY_ENTER, SK_RETURN }, + { KEY_LEFTCTRL, SK_LCTRL }, + { KEY_A, SK_a }, + { KEY_S, SK_s }, + { KEY_D, SK_d }, + { KEY_F, SK_f }, + { KEY_G, SK_g }, + { KEY_H, SK_h }, + { KEY_J, SK_j }, + { KEY_K, SK_k }, + { KEY_L, SK_l }, + { KEY_SEMICOLON, SK_SEMICOLON }, + { KEY_APOSTROPHE, SK_QUOTE }, + { KEY_GRAVE, SK_BACKQUOTE }, + { KEY_LEFTSHIFT, SK_LSHIFT }, + { KEY_BACKSLASH, SK_BACKSLASH }, + { KEY_Z, SK_z }, + { KEY_X, SK_x }, + { KEY_C, SK_c }, + { KEY_V, SK_v }, + { KEY_B, SK_b }, + { KEY_N, SK_n }, + { KEY_M, SK_m }, + { KEY_COMMA, SK_COMMA }, + { KEY_DOT, SK_PERIOD }, + { KEY_SLASH, SK_SLASH }, + { KEY_RIGHTSHIFT, SK_RSHIFT }, + { KEY_KPASTERISK, SK_KP_MULTIPLY }, + { KEY_LEFTALT, SK_LALT }, + { KEY_SPACE, SK_SPACE }, + { KEY_CAPSLOCK, SK_CAPSLOCK }, + { KEY_F1, SK_F1 }, + { KEY_F2, SK_F2 }, + { KEY_F3, SK_F3 }, + { KEY_F4, SK_F4 }, + { KEY_F5, SK_F5 }, + { KEY_F6, SK_F6 }, + { KEY_F7, SK_F7 }, + { KEY_F8, SK_F8 }, + { KEY_F9, SK_F9 }, + { KEY_F10, SK_F10 }, + { KEY_NUMLOCK, SK_NUMLOCK }, + { KEY_SCROLLLOCK, SK_SCROLLOCK }, + { KEY_KP7, SK_KP7 }, + { KEY_KP8, SK_KP8 }, + { KEY_KP9, SK_KP9 }, + { KEY_KPMINUS, SK_KP_MINUS }, + { KEY_KP4, SK_KP4 }, + { KEY_KP5, SK_KP5 }, + { KEY_KP6, SK_KP6 }, + { KEY_KPPLUS, SK_KP_PLUS }, + { KEY_KP1, SK_KP1 }, + { KEY_KP2, SK_KP2 }, + { KEY_KP3, SK_KP3 }, + { KEY_KP0, SK_KP0 }, + { KEY_KPDOT, SK_KP_PERIOD }, - { KEY_F11, SK_F11 }, - { KEY_F12, SK_F12 }, + { KEY_F11, SK_F11 }, + { KEY_F12, SK_F12 }, - { KEY_KPENTER, SK_KP_ENTER }, - { KEY_RIGHTCTRL, SK_RCTRL }, - { KEY_KPSLASH, SK_KP_DIVIDE }, - { KEY_SYSRQ, SK_PRINT }, - { KEY_RIGHTALT, SK_RALT }, + { KEY_KPENTER, SK_KP_ENTER }, + { KEY_RIGHTCTRL, SK_RCTRL }, + { KEY_KPSLASH, SK_KP_DIVIDE }, + { KEY_SYSRQ, SK_PRINT }, + { KEY_RIGHTALT, SK_RALT }, - { KEY_HOME, SK_HOME }, - { KEY_UP, SK_UP }, - { KEY_PAGEUP, SK_PAGEUP }, - { KEY_LEFT, SK_LEFT }, - { KEY_RIGHT, SK_RIGHT }, - { KEY_END, SK_END }, - { KEY_DOWN, SK_DOWN }, - { KEY_PAGEDOWN, SK_PAGEDOWN }, - { KEY_INSERT, SK_INSERT }, - { KEY_DELETE, SK_DELETE }, + { KEY_HOME, SK_HOME }, + { KEY_UP, SK_UP }, + { KEY_PAGEUP, SK_PAGEUP }, + { KEY_LEFT, SK_LEFT }, + { KEY_RIGHT, SK_RIGHT }, + { KEY_END, SK_END }, + { KEY_DOWN, SK_DOWN }, + { KEY_PAGEDOWN, SK_PAGEDOWN }, + { KEY_INSERT, SK_INSERT }, + { KEY_DELETE, SK_DELETE }, - { KEY_PAUSE, SK_PAUSE }, + { KEY_PAUSE, SK_PAUSE }, }; static void init_lut(void) { - memset(keysym_lut, 0, sizeof(keysym_lut)); - for (unsigned i = 0; i < sizeof(lut_binds) / sizeof(lut_binds[0]); i++) - keysym_lut[lut_binds[i].sk] = lut_binds[i].x; + memset(keysym_lut, 0, sizeof(keysym_lut)); + for (unsigned i = 0; i < sizeof(lut_binds) / sizeof(lut_binds[0]); i++) + keysym_lut[lut_binds[i].sk] = lut_binds[i].x; } static void linuxraw_resetKbmd() { - if (oldKbmd != 0xFFFF) - { - ioctl(0, KDSKBMODE, oldKbmd); - tcsetattr(0, TCSAFLUSH, &oldTerm); - oldKbmd = 0xFFFF; - } + if (oldKbmd != 0xFFFF) + { + ioctl(0, KDSKBMODE, oldKbmd); + tcsetattr(0, TCSAFLUSH, &oldTerm); + oldKbmd = 0xFFFF; + } } static void linuxraw_exitGracefully(int sig) { - linuxraw_resetKbmd(); - signal(sig, SIG_DFL); - kill(getpid(), sig); + linuxraw_resetKbmd(); + signal(sig, SIG_DFL); + kill(getpid(), sig); } static void *linuxraw_input_init(void) { - // only work on terminals - if (!isatty(0)) - return NULL; + // only work on terminals + if (!isatty(0)) + return NULL; - linuxraw_input_t *linuxraw = (linuxraw_input_t*)calloc(1, sizeof(*linuxraw)); - if (!linuxraw) - return NULL; + linuxraw_input_t *linuxraw = (linuxraw_input_t*)calloc(1, sizeof(*linuxraw)); + if (!linuxraw) + return NULL; - if (oldKbmd == 0xFFFF) - { - tcgetattr(0, &oldTerm); - newTerm = oldTerm; - newTerm.c_lflag &= ~(ECHO | ICANON | ISIG); - newTerm.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); - newTerm.c_cc[VMIN] = 0; - newTerm.c_cc[VTIME] = 0; + if (oldKbmd == 0xFFFF) + { + tcgetattr(0, &oldTerm); + newTerm = oldTerm; + newTerm.c_lflag &= ~(ECHO | ICANON | ISIG); + newTerm.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); + newTerm.c_cc[VMIN] = 0; + newTerm.c_cc[VTIME] = 0; - if (ioctl(0, KDGKBMODE, &oldKbmd) != 0) - return NULL; - } + if (ioctl(0, KDGKBMODE, &oldKbmd) != 0) + return NULL; + } - tcsetattr(0, TCSAFLUSH, &newTerm); + tcsetattr(0, TCSAFLUSH, &newTerm); - if (ioctl(0, KDSKBMODE, K_MEDIUMRAW) != 0) - { - linuxraw_resetKbmd(); - return NULL; - } + if (ioctl(0, KDSKBMODE, K_MEDIUMRAW) != 0) + { + linuxraw_resetKbmd(); + return NULL; + } - // trap some standard termination codes so we can restore the keyboard before we lose control - signal(SIGABRT, linuxraw_exitGracefully); - signal(SIGBUS, linuxraw_exitGracefully); - signal(SIGFPE, linuxraw_exitGracefully); - signal(SIGILL, linuxraw_exitGracefully); - signal(SIGINT, linuxraw_exitGracefully); - signal(SIGQUIT, linuxraw_exitGracefully); - signal(SIGSEGV, linuxraw_exitGracefully); - signal(SIGTERM, linuxraw_exitGracefully); + // trap some standard termination codes so we can restore the keyboard before we lose control + signal(SIGABRT, linuxraw_exitGracefully); + signal(SIGBUS, linuxraw_exitGracefully); + signal(SIGFPE, linuxraw_exitGracefully); + signal(SIGILL, linuxraw_exitGracefully); + signal(SIGINT, linuxraw_exitGracefully); + signal(SIGQUIT, linuxraw_exitGracefully); + signal(SIGSEGV, linuxraw_exitGracefully); + signal(SIGTERM, linuxraw_exitGracefully); - atexit(linuxraw_resetKbmd); + atexit(linuxraw_resetKbmd); - linuxraw->sdl = (sdl_input_t*)input_sdl.init(); - if (!linuxraw->sdl) - { - linuxraw_resetKbmd(); - free(linuxraw); - return NULL; - } + linuxraw->sdl = (sdl_input_t*)input_sdl.init(); + if (!linuxraw->sdl) + { + linuxraw_resetKbmd(); + free(linuxraw); + return NULL; + } - init_lut(); + init_lut(); - linuxraw->sdl->use_keyboard = false; - return linuxraw; + linuxraw->sdl->use_keyboard = false; + return linuxraw; } static bool linuxraw_key_pressed(linuxraw_input_t *linuxraw, int key) { - return linuxraw->state[keysym_lut[key]]; + return linuxraw->state[keysym_lut[key]]; } static bool linuxraw_is_pressed(linuxraw_input_t *linuxraw, const struct snes_keybind *binds, unsigned id) { - if (id < RARCH_BIND_LIST_END) - { - const struct snes_keybind *bind = &binds[id]; - return bind->valid && linuxraw_key_pressed(linuxraw, binds[id].key); - } - else - return false; + if (id < RARCH_BIND_LIST_END) + { + const struct snes_keybind *bind = &binds[id]; + return bind->valid && linuxraw_key_pressed(linuxraw, binds[id].key); + } + else + return false; } static bool linuxraw_bind_button_pressed(void *data, int key) { - linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; - return linuxraw_is_pressed(linuxraw, g_settings.input.binds[0], key) || - input_sdl.key_pressed(linuxraw->sdl, key); + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + return linuxraw_is_pressed(linuxraw, g_settings.input.binds[0], key) || + input_sdl.key_pressed(linuxraw->sdl, key); } static int16_t linuxraw_input_state(void *data, const struct snes_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id) { - linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; - switch (device) - { - case RETRO_DEVICE_JOYPAD: - return linuxraw_is_pressed(linuxraw, binds[port], id) || - input_sdl.input_state(linuxraw->sdl, binds, port, device, index, id); + switch (device) + { + case RETRO_DEVICE_JOYPAD: + return linuxraw_is_pressed(linuxraw, binds[port], id) || + input_sdl.input_state(linuxraw->sdl, binds, port, device, index, id); - default: - return 0; - } + default: + return 0; + } } static void linuxraw_input_free(void *data) { - linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; - input_sdl.free(linuxraw->sdl); - linuxraw_resetKbmd(); - free(data); + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + input_sdl.free(linuxraw->sdl); + linuxraw_resetKbmd(); + free(data); } static void linuxraw_input_poll(void *data) { - linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; - uint8_t c; - uint16_t t; + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + uint8_t c; + uint16_t t; - while (read(0, &c, 1)) - { - bool pressed = !(c & 0x80); - c &= ~0x80; + while (read(0, &c, 1)) + { + bool pressed = !(c & 0x80); + c &= ~0x80; - // ignore extended scancodes - if (!c) - read(0, &t, 2); + // ignore extended scancodes + if (!c) + read(0, &t, 2); - linuxraw->state[c] = pressed; - } + linuxraw->state[c] = pressed; + } - input_sdl.poll(linuxraw->sdl); + input_sdl.poll(linuxraw->sdl); } const input_driver_t input_linuxraw = { - linuxraw_input_init, - linuxraw_input_poll, - linuxraw_input_state, - linuxraw_bind_button_pressed, - linuxraw_input_free, - "linuxraw" + linuxraw_input_init, + linuxraw_input_poll, + linuxraw_input_state, + linuxraw_bind_button_pressed, + linuxraw_input_free, + "linuxraw" }; diff --git a/input/linuxraw_input.h b/input/linuxraw_input.h index 5ad9c2c95f..8658d02a1e 100644 --- a/input/linuxraw_input.h +++ b/input/linuxraw_input.h @@ -22,8 +22,8 @@ typedef struct linuxraw_input { - sdl_input_t *sdl; - bool state[0x80]; + sdl_input_t *sdl; + bool state[0x80]; } linuxraw_input_t; #endif From 0337e4fc0f4151c2ddfe8df00d64b7e81d37cd6c Mon Sep 17 00:00:00 2001 From: Toad King Date: Tue, 19 Jun 2012 13:40:49 -0400 Subject: [PATCH 17/21] move SIGINT and SIGTERM handlers to video driver --- gfx/rpi.c | 13 ++++++++++++- input/linuxraw_input.c | 2 -- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/gfx/rpi.c b/gfx/rpi.c index f90538e95c..43d5f65fe7 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -66,6 +66,14 @@ typedef struct { #endif } rpi_t; +static bool rpi_shutdown = false; + +static void rpi_kill(int sig) +{ + (void)sig; + rpi_shutdown = true; +} + static void rpi_set_nonblock_state(void *data, bool state) { rpi_t *rpi = (rpi_t*)data; @@ -211,6 +219,9 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v } #endif + signal(SIGINT, rpi_kill); + signal(SIGTERM, rpi_kill); + return rpi; } @@ -402,7 +413,7 @@ static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned he static bool rpi_alive(void *data) { (void)data; - return true; + return !rpi_shutdown; } static bool rpi_focus(void *data) diff --git a/input/linuxraw_input.c b/input/linuxraw_input.c index c96eb52616..91ed610ea5 100644 --- a/input/linuxraw_input.c +++ b/input/linuxraw_input.c @@ -204,10 +204,8 @@ static void *linuxraw_input_init(void) signal(SIGBUS, linuxraw_exitGracefully); signal(SIGFPE, linuxraw_exitGracefully); signal(SIGILL, linuxraw_exitGracefully); - signal(SIGINT, linuxraw_exitGracefully); signal(SIGQUIT, linuxraw_exitGracefully); signal(SIGSEGV, linuxraw_exitGracefully); - signal(SIGTERM, linuxraw_exitGracefully); atexit(linuxraw_resetKbmd); From 3e1b621e7ae88d03c829d4e7f02c997185c7ddbc Mon Sep 17 00:00:00 2001 From: Toad King Date: Tue, 19 Jun 2012 14:14:00 -0400 Subject: [PATCH 18/21] signal -> sigaction --- gfx/rpi.c | 12 ++++++++---- input/linuxraw_input.c | 17 ++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/gfx/rpi.c b/gfx/rpi.c index 43d5f65fe7..6a516b83a9 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -66,12 +66,12 @@ typedef struct { #endif } rpi_t; -static bool rpi_shutdown = false; +static volatile sig_atomic_t rpi_shutdown = 0; static void rpi_kill(int sig) { (void)sig; - rpi_shutdown = true; + rpi_shutdown = 1; } static void rpi_set_nonblock_state(void *data, bool state) @@ -219,8 +219,12 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v } #endif - signal(SIGINT, rpi_kill); - signal(SIGTERM, rpi_kill); + struct sigaction sa; + sa.sa_handler = rpi_kill; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); return rpi; } diff --git a/input/linuxraw_input.c b/input/linuxraw_input.c index 91ed610ea5..a91dc28004 100644 --- a/input/linuxraw_input.c +++ b/input/linuxraw_input.c @@ -164,7 +164,6 @@ static void linuxraw_resetKbmd() static void linuxraw_exitGracefully(int sig) { linuxraw_resetKbmd(); - signal(sig, SIG_DFL); kill(getpid(), sig); } @@ -199,13 +198,17 @@ static void *linuxraw_input_init(void) return NULL; } + struct sigaction sa; + sa.sa_handler = linuxraw_exitGracefully; + sa.sa_flags = SA_RESTART | SA_RESETHAND; + sigemptyset(&sa.sa_mask); // trap some standard termination codes so we can restore the keyboard before we lose control - signal(SIGABRT, linuxraw_exitGracefully); - signal(SIGBUS, linuxraw_exitGracefully); - signal(SIGFPE, linuxraw_exitGracefully); - signal(SIGILL, linuxraw_exitGracefully); - signal(SIGQUIT, linuxraw_exitGracefully); - signal(SIGSEGV, linuxraw_exitGracefully); + sigaction(SIGABRT, &sa, NULL); + sigaction(SIGBUS, &sa, NULL); + sigaction(SIGFPE, &sa, NULL); + sigaction(SIGILL, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGSEGV, &sa, NULL); atexit(linuxraw_resetKbmd); From ed14c8c6b86343029d403d3b6b3925baff1f2dcb Mon Sep 17 00:00:00 2001 From: Toad King Date: Tue, 19 Jun 2012 14:49:38 -0400 Subject: [PATCH 19/21] misc. fixes add ctrl+c handler to linuxraw_input --- gfx/rpi.c | 28 +- input/linuxraw_input.c | 609 +++++++++++++++++++++-------------------- input/linuxraw_input.h | 6 +- 3 files changed, 318 insertions(+), 325 deletions(-) diff --git a/gfx/rpi.c b/gfx/rpi.c index 6a516b83a9..b718428c8e 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -14,7 +14,6 @@ * If not, see . */ -#include #include #include #include @@ -24,9 +23,7 @@ #include #include "../libretro.h" #include "../general.h" -//#include "../input/linuxraw_input.h" -// SDL include messing with some defines -typedef struct linuxraw_input linuxraw_input_t; +#include "../input/linuxraw_input.h" #include "../driver.h" #ifdef HAVE_FREETYPE @@ -113,24 +110,24 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v // get an EGL display connection rpi->mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - assert(rpi->mDisplay != EGL_NO_DISPLAY); + rarch_assert(rpi->mDisplay != EGL_NO_DISPLAY); // initialize the EGL display connection result = eglInitialize(rpi->mDisplay, NULL, NULL); - assert(result != EGL_FALSE); + rarch_assert(result != EGL_FALSE); eglBindAPI(EGL_OPENVG_API); // get an appropriate EGL frame buffer configuration result = eglChooseConfig(rpi->mDisplay, attribute_list, &config, 1, &num_config); - assert(result != EGL_FALSE); + rarch_assert(result != EGL_FALSE); // create an EGL rendering context rpi->mContext = eglCreateContext(rpi->mDisplay, config, EGL_NO_CONTEXT, NULL); - assert(rpi->mContext != EGL_NO_CONTEXT); + rarch_assert(rpi->mContext != EGL_NO_CONTEXT); // create an EGL window surface success = graphics_get_display_size(0 /* LCD */, &rpi->mScreenWidth, &rpi->mScreenHeight); - assert(success >= 0); + rarch_assert(success >= 0); dst_rect.x = 0; dst_rect.y = 0; @@ -156,11 +153,11 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v vc_dispmanx_update_submit_sync(dispman_update); rpi->mSurface = eglCreateWindowSurface(rpi->mDisplay, config, &nativewindow, NULL); - assert(rpi->mSurface != EGL_NO_SURFACE); + rarch_assert(rpi->mSurface != EGL_NO_SURFACE); // connect the context to the surface result = eglMakeCurrent(rpi->mDisplay, rpi->mSurface, rpi->mSurface, rpi->mContext); - assert(result != EGL_FALSE); + rarch_assert(result != EGL_FALSE); rpi->mTexType = video->rgb32 ? VG_sABGR_8888 : VG_sARGB_1555; rpi->mKeepAspect = video->force_aspect; @@ -426,12 +423,6 @@ static bool rpi_focus(void *data) return true; } -static void rpi_set_rotation(void *data, unsigned rotation) -{ - (void)data; - (void)rotation; -} - const video_driver_t video_rpi = { rpi_init, rpi_frame, @@ -440,6 +431,5 @@ const video_driver_t video_rpi = { rpi_focus, NULL, rpi_free, - "rpi", - rpi_set_rotation, + "rpi" }; diff --git a/input/linuxraw_input.c b/input/linuxraw_input.c index a91dc28004..97fec4e17e 100644 --- a/input/linuxraw_input.c +++ b/input/linuxraw_input.c @@ -1,303 +1,306 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2012 - Hans-Kristian Arntzen - * Copyright (C) 2012 - Michael Lelli - * - * 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 -#include -#include -#include -#include -#include -#include "../general.h" -#include "linuxraw_input.h" -#include "rarch_sdl_input.h" - -static long oldKbmd = 0xFFFF; -static struct termios oldTerm, newTerm; - -struct key_bind -{ - uint8_t x; - enum rarch_key sk; -}; - -static unsigned keysym_lut[SK_LAST]; -static const struct key_bind lut_binds[] = { - { KEY_ESC, SK_ESCAPE }, - { KEY_1, SK_1 }, - { KEY_2, SK_2 }, - { KEY_3, SK_3}, - { KEY_4, SK_4 }, - { KEY_5, SK_5 }, - { KEY_6, SK_6 }, - { KEY_7, SK_7 }, - { KEY_8, SK_8 }, - { KEY_9, SK_9 }, - { KEY_0, SK_0 }, - { KEY_MINUS, SK_MINUS }, - { KEY_EQUAL, SK_EQUALS }, - { KEY_BACKSPACE, SK_BACKSPACE }, - { KEY_TAB, SK_TAB }, - { KEY_Q, SK_q }, - { KEY_W, SK_w }, - { KEY_E, SK_e }, - { KEY_R, SK_r }, - { KEY_T, SK_t }, - { KEY_Y, SK_y }, - { KEY_U, SK_u }, - { KEY_I, SK_i }, - { KEY_O, SK_o }, - { KEY_P, SK_p }, - { KEY_LEFTBRACE, SK_LEFTBRACKET }, - { KEY_RIGHTBRACE, SK_RIGHTBRACKET }, - { KEY_ENTER, SK_RETURN }, - { KEY_LEFTCTRL, SK_LCTRL }, - { KEY_A, SK_a }, - { KEY_S, SK_s }, - { KEY_D, SK_d }, - { KEY_F, SK_f }, - { KEY_G, SK_g }, - { KEY_H, SK_h }, - { KEY_J, SK_j }, - { KEY_K, SK_k }, - { KEY_L, SK_l }, - { KEY_SEMICOLON, SK_SEMICOLON }, - { KEY_APOSTROPHE, SK_QUOTE }, - { KEY_GRAVE, SK_BACKQUOTE }, - { KEY_LEFTSHIFT, SK_LSHIFT }, - { KEY_BACKSLASH, SK_BACKSLASH }, - { KEY_Z, SK_z }, - { KEY_X, SK_x }, - { KEY_C, SK_c }, - { KEY_V, SK_v }, - { KEY_B, SK_b }, - { KEY_N, SK_n }, - { KEY_M, SK_m }, - { KEY_COMMA, SK_COMMA }, - { KEY_DOT, SK_PERIOD }, - { KEY_SLASH, SK_SLASH }, - { KEY_RIGHTSHIFT, SK_RSHIFT }, - { KEY_KPASTERISK, SK_KP_MULTIPLY }, - { KEY_LEFTALT, SK_LALT }, - { KEY_SPACE, SK_SPACE }, - { KEY_CAPSLOCK, SK_CAPSLOCK }, - { KEY_F1, SK_F1 }, - { KEY_F2, SK_F2 }, - { KEY_F3, SK_F3 }, - { KEY_F4, SK_F4 }, - { KEY_F5, SK_F5 }, - { KEY_F6, SK_F6 }, - { KEY_F7, SK_F7 }, - { KEY_F8, SK_F8 }, - { KEY_F9, SK_F9 }, - { KEY_F10, SK_F10 }, - { KEY_NUMLOCK, SK_NUMLOCK }, - { KEY_SCROLLLOCK, SK_SCROLLOCK }, - { KEY_KP7, SK_KP7 }, - { KEY_KP8, SK_KP8 }, - { KEY_KP9, SK_KP9 }, - { KEY_KPMINUS, SK_KP_MINUS }, - { KEY_KP4, SK_KP4 }, - { KEY_KP5, SK_KP5 }, - { KEY_KP6, SK_KP6 }, - { KEY_KPPLUS, SK_KP_PLUS }, - { KEY_KP1, SK_KP1 }, - { KEY_KP2, SK_KP2 }, - { KEY_KP3, SK_KP3 }, - { KEY_KP0, SK_KP0 }, - { KEY_KPDOT, SK_KP_PERIOD }, - - { KEY_F11, SK_F11 }, - { KEY_F12, SK_F12 }, - - { KEY_KPENTER, SK_KP_ENTER }, - { KEY_RIGHTCTRL, SK_RCTRL }, - { KEY_KPSLASH, SK_KP_DIVIDE }, - { KEY_SYSRQ, SK_PRINT }, - { KEY_RIGHTALT, SK_RALT }, - - { KEY_HOME, SK_HOME }, - { KEY_UP, SK_UP }, - { KEY_PAGEUP, SK_PAGEUP }, - { KEY_LEFT, SK_LEFT }, - { KEY_RIGHT, SK_RIGHT }, - { KEY_END, SK_END }, - { KEY_DOWN, SK_DOWN }, - { KEY_PAGEDOWN, SK_PAGEDOWN }, - { KEY_INSERT, SK_INSERT }, - { KEY_DELETE, SK_DELETE }, - - { KEY_PAUSE, SK_PAUSE }, -}; - -static void init_lut(void) -{ - memset(keysym_lut, 0, sizeof(keysym_lut)); - for (unsigned i = 0; i < sizeof(lut_binds) / sizeof(lut_binds[0]); i++) - keysym_lut[lut_binds[i].sk] = lut_binds[i].x; -} - -static void linuxraw_resetKbmd() -{ - if (oldKbmd != 0xFFFF) - { - ioctl(0, KDSKBMODE, oldKbmd); - tcsetattr(0, TCSAFLUSH, &oldTerm); - oldKbmd = 0xFFFF; - } -} - -static void linuxraw_exitGracefully(int sig) -{ - linuxraw_resetKbmd(); - kill(getpid(), sig); -} - -static void *linuxraw_input_init(void) -{ - // only work on terminals - if (!isatty(0)) - return NULL; - - linuxraw_input_t *linuxraw = (linuxraw_input_t*)calloc(1, sizeof(*linuxraw)); - if (!linuxraw) - return NULL; - - if (oldKbmd == 0xFFFF) - { - tcgetattr(0, &oldTerm); - newTerm = oldTerm; - newTerm.c_lflag &= ~(ECHO | ICANON | ISIG); - newTerm.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); - newTerm.c_cc[VMIN] = 0; - newTerm.c_cc[VTIME] = 0; - - if (ioctl(0, KDGKBMODE, &oldKbmd) != 0) - return NULL; - } - - tcsetattr(0, TCSAFLUSH, &newTerm); - - if (ioctl(0, KDSKBMODE, K_MEDIUMRAW) != 0) - { - linuxraw_resetKbmd(); - return NULL; - } - - struct sigaction sa; - sa.sa_handler = linuxraw_exitGracefully; - sa.sa_flags = SA_RESTART | SA_RESETHAND; - sigemptyset(&sa.sa_mask); - // trap some standard termination codes so we can restore the keyboard before we lose control - sigaction(SIGABRT, &sa, NULL); - sigaction(SIGBUS, &sa, NULL); - sigaction(SIGFPE, &sa, NULL); - sigaction(SIGILL, &sa, NULL); - sigaction(SIGQUIT, &sa, NULL); - sigaction(SIGSEGV, &sa, NULL); - - atexit(linuxraw_resetKbmd); - - linuxraw->sdl = (sdl_input_t*)input_sdl.init(); - if (!linuxraw->sdl) - { - linuxraw_resetKbmd(); - free(linuxraw); - return NULL; - } - - init_lut(); - - linuxraw->sdl->use_keyboard = false; - return linuxraw; -} - -static bool linuxraw_key_pressed(linuxraw_input_t *linuxraw, int key) -{ - return linuxraw->state[keysym_lut[key]]; -} - -static bool linuxraw_is_pressed(linuxraw_input_t *linuxraw, const struct snes_keybind *binds, unsigned id) -{ - if (id < RARCH_BIND_LIST_END) - { - const struct snes_keybind *bind = &binds[id]; - return bind->valid && linuxraw_key_pressed(linuxraw, binds[id].key); - } - else - return false; -} - -static bool linuxraw_bind_button_pressed(void *data, int key) -{ - linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; - return linuxraw_is_pressed(linuxraw, g_settings.input.binds[0], key) || - input_sdl.key_pressed(linuxraw->sdl, key); -} - -static int16_t linuxraw_input_state(void *data, const struct snes_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id) -{ - linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; - - switch (device) - { - case RETRO_DEVICE_JOYPAD: - return linuxraw_is_pressed(linuxraw, binds[port], id) || - input_sdl.input_state(linuxraw->sdl, binds, port, device, index, id); - - default: - return 0; - } -} - -static void linuxraw_input_free(void *data) -{ - linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; - input_sdl.free(linuxraw->sdl); - linuxraw_resetKbmd(); - free(data); -} - -static void linuxraw_input_poll(void *data) -{ - linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; - uint8_t c; - uint16_t t; - - while (read(0, &c, 1)) - { - bool pressed = !(c & 0x80); - c &= ~0x80; - - // ignore extended scancodes - if (!c) - read(0, &t, 2); - - linuxraw->state[c] = pressed; - } - - input_sdl.poll(linuxraw->sdl); -} - -const input_driver_t input_linuxraw = { - linuxraw_input_init, - linuxraw_input_poll, - linuxraw_input_state, - linuxraw_bind_button_pressed, - linuxraw_input_free, - "linuxraw" -}; +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2012 - Michael Lelli + * + * 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 +#include +#include +#include +#include +#include +#include "../general.h" +#include "linuxraw_input.h" +#include "rarch_sdl_input.h" + +static long oldKbmd = 0xFFFF; +static struct termios oldTerm, newTerm; + +struct key_bind +{ + uint8_t x; + enum rarch_key sk; +}; + +static unsigned keysym_lut[SK_LAST]; +static const struct key_bind lut_binds[] = { + { KEY_ESC, SK_ESCAPE }, + { KEY_1, SK_1 }, + { KEY_2, SK_2 }, + { KEY_3, SK_3}, + { KEY_4, SK_4 }, + { KEY_5, SK_5 }, + { KEY_6, SK_6 }, + { KEY_7, SK_7 }, + { KEY_8, SK_8 }, + { KEY_9, SK_9 }, + { KEY_0, SK_0 }, + { KEY_MINUS, SK_MINUS }, + { KEY_EQUAL, SK_EQUALS }, + { KEY_BACKSPACE, SK_BACKSPACE }, + { KEY_TAB, SK_TAB }, + { KEY_Q, SK_q }, + { KEY_W, SK_w }, + { KEY_E, SK_e }, + { KEY_R, SK_r }, + { KEY_T, SK_t }, + { KEY_Y, SK_y }, + { KEY_U, SK_u }, + { KEY_I, SK_i }, + { KEY_O, SK_o }, + { KEY_P, SK_p }, + { KEY_LEFTBRACE, SK_LEFTBRACKET }, + { KEY_RIGHTBRACE, SK_RIGHTBRACKET }, + { KEY_ENTER, SK_RETURN }, + { KEY_LEFTCTRL, SK_LCTRL }, + { KEY_A, SK_a }, + { KEY_S, SK_s }, + { KEY_D, SK_d }, + { KEY_F, SK_f }, + { KEY_G, SK_g }, + { KEY_H, SK_h }, + { KEY_J, SK_j }, + { KEY_K, SK_k }, + { KEY_L, SK_l }, + { KEY_SEMICOLON, SK_SEMICOLON }, + { KEY_APOSTROPHE, SK_QUOTE }, + { KEY_GRAVE, SK_BACKQUOTE }, + { KEY_LEFTSHIFT, SK_LSHIFT }, + { KEY_BACKSLASH, SK_BACKSLASH }, + { KEY_Z, SK_z }, + { KEY_X, SK_x }, + { KEY_C, SK_c }, + { KEY_V, SK_v }, + { KEY_B, SK_b }, + { KEY_N, SK_n }, + { KEY_M, SK_m }, + { KEY_COMMA, SK_COMMA }, + { KEY_DOT, SK_PERIOD }, + { KEY_SLASH, SK_SLASH }, + { KEY_RIGHTSHIFT, SK_RSHIFT }, + { KEY_KPASTERISK, SK_KP_MULTIPLY }, + { KEY_LEFTALT, SK_LALT }, + { KEY_SPACE, SK_SPACE }, + { KEY_CAPSLOCK, SK_CAPSLOCK }, + { KEY_F1, SK_F1 }, + { KEY_F2, SK_F2 }, + { KEY_F3, SK_F3 }, + { KEY_F4, SK_F4 }, + { KEY_F5, SK_F5 }, + { KEY_F6, SK_F6 }, + { KEY_F7, SK_F7 }, + { KEY_F8, SK_F8 }, + { KEY_F9, SK_F9 }, + { KEY_F10, SK_F10 }, + { KEY_NUMLOCK, SK_NUMLOCK }, + { KEY_SCROLLLOCK, SK_SCROLLOCK }, + { KEY_KP7, SK_KP7 }, + { KEY_KP8, SK_KP8 }, + { KEY_KP9, SK_KP9 }, + { KEY_KPMINUS, SK_KP_MINUS }, + { KEY_KP4, SK_KP4 }, + { KEY_KP5, SK_KP5 }, + { KEY_KP6, SK_KP6 }, + { KEY_KPPLUS, SK_KP_PLUS }, + { KEY_KP1, SK_KP1 }, + { KEY_KP2, SK_KP2 }, + { KEY_KP3, SK_KP3 }, + { KEY_KP0, SK_KP0 }, + { KEY_KPDOT, SK_KP_PERIOD }, + + { KEY_F11, SK_F11 }, + { KEY_F12, SK_F12 }, + + { KEY_KPENTER, SK_KP_ENTER }, + { KEY_RIGHTCTRL, SK_RCTRL }, + { KEY_KPSLASH, SK_KP_DIVIDE }, + { KEY_SYSRQ, SK_PRINT }, + { KEY_RIGHTALT, SK_RALT }, + + { KEY_HOME, SK_HOME }, + { KEY_UP, SK_UP }, + { KEY_PAGEUP, SK_PAGEUP }, + { KEY_LEFT, SK_LEFT }, + { KEY_RIGHT, SK_RIGHT }, + { KEY_END, SK_END }, + { KEY_DOWN, SK_DOWN }, + { KEY_PAGEDOWN, SK_PAGEDOWN }, + { KEY_INSERT, SK_INSERT }, + { KEY_DELETE, SK_DELETE }, + + { KEY_PAUSE, SK_PAUSE }, +}; + +static void init_lut(void) +{ + memset(keysym_lut, 0, sizeof(keysym_lut)); + for (unsigned i = 0; i < sizeof(lut_binds) / sizeof(lut_binds[0]); i++) + keysym_lut[lut_binds[i].sk] = lut_binds[i].x; +} + +static void linuxraw_resetKbmd() +{ + if (oldKbmd != 0xFFFF) + { + ioctl(0, KDSKBMODE, oldKbmd); + tcsetattr(0, TCSAFLUSH, &oldTerm); + oldKbmd = 0xFFFF; + } +} + +static void linuxraw_exitGracefully(int sig) +{ + linuxraw_resetKbmd(); + kill(getpid(), sig); +} + +static void *linuxraw_input_init(void) +{ + // only work on terminals + if (!isatty(0)) + return NULL; + + linuxraw_input_t *linuxraw = (linuxraw_input_t*)calloc(1, sizeof(*linuxraw)); + if (!linuxraw) + return NULL; + + if (oldKbmd == 0xFFFF) + { + tcgetattr(0, &oldTerm); + newTerm = oldTerm; + newTerm.c_lflag &= ~(ECHO | ICANON | ISIG); + newTerm.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); + newTerm.c_cc[VMIN] = 0; + newTerm.c_cc[VTIME] = 0; + + if (ioctl(0, KDGKBMODE, &oldKbmd) != 0) + return NULL; + } + + tcsetattr(0, TCSAFLUSH, &newTerm); + + if (ioctl(0, KDSKBMODE, K_MEDIUMRAW) != 0) + { + linuxraw_resetKbmd(); + return NULL; + } + + struct sigaction sa; + sa.sa_handler = linuxraw_exitGracefully; + sa.sa_flags = SA_RESTART | SA_RESETHAND; + sigemptyset(&sa.sa_mask); + // trap some standard termination codes so we can restore the keyboard before we lose control + sigaction(SIGABRT, &sa, NULL); + sigaction(SIGBUS, &sa, NULL); + sigaction(SIGFPE, &sa, NULL); + sigaction(SIGILL, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGSEGV, &sa, NULL); + + atexit(linuxraw_resetKbmd); + + linuxraw->sdl = (sdl_input_t*)input_sdl.init(); + if (!linuxraw->sdl) + { + linuxraw_resetKbmd(); + free(linuxraw); + return NULL; + } + + init_lut(); + + linuxraw->sdl->use_keyboard = false; + return linuxraw; +} + +static bool linuxraw_key_pressed(linuxraw_input_t *linuxraw, int key) +{ + return linuxraw->state[keysym_lut[key]]; +} + +static bool linuxraw_is_pressed(linuxraw_input_t *linuxraw, const struct snes_keybind *binds, unsigned id) +{ + if (id < RARCH_BIND_LIST_END) + { + const struct snes_keybind *bind = &binds[id]; + return bind->valid && linuxraw_key_pressed(linuxraw, binds[id].key); + } + else + return false; +} + +static bool linuxraw_bind_button_pressed(void *data, int key) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + return linuxraw_is_pressed(linuxraw, g_settings.input.binds[0], key) || + input_sdl.key_pressed(linuxraw->sdl, key); +} + +static int16_t linuxraw_input_state(void *data, const struct snes_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + + switch (device) + { + case RETRO_DEVICE_JOYPAD: + return linuxraw_is_pressed(linuxraw, binds[port], id) || + input_sdl.input_state(linuxraw->sdl, binds, port, device, index, id); + + default: + return 0; + } +} + +static void linuxraw_input_free(void *data) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + input_sdl.free(linuxraw->sdl); + linuxraw_resetKbmd(); + free(data); +} + +static void linuxraw_input_poll(void *data) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + uint8_t c; + uint16_t t; + + while (read(0, &c, 1) > 0) + { + bool pressed = !(c & 0x80); + c &= ~0x80; + + // ignore extended scancodes + if (!c) + read(0, &t, 2); + else + linuxraw->state[c] = pressed; + } + + if (linuxraw->state[KEY_C] && (linuxraw->state[KEY_LEFTCTRL] || linuxraw->state[KEY_RIGHTCTRL])) + kill(getpid(), SIGINT); + + input_sdl.poll(linuxraw->sdl); +} + +const input_driver_t input_linuxraw = { + linuxraw_input_init, + linuxraw_input_poll, + linuxraw_input_state, + linuxraw_bind_button_pressed, + linuxraw_input_free, + "linuxraw" +}; diff --git a/input/linuxraw_input.h b/input/linuxraw_input.h index 8658d02a1e..710ffdf5c6 100644 --- a/input/linuxraw_input.h +++ b/input/linuxraw_input.h @@ -14,12 +14,12 @@ * If not, see . */ -#include "../general.h" -#include "rarch_sdl_input.h" - #ifndef _LINUXRAW_INPUT_H #define _LINUXRAW_INPUT_H +#include "../general.h" +#include "rarch_sdl_input.h" + typedef struct linuxraw_input { sdl_input_t *sdl; From 92f345cb5e5beec09d148c80399bea4c8959156a Mon Sep 17 00:00:00 2001 From: Toad King Date: Tue, 19 Jun 2012 14:55:06 -0400 Subject: [PATCH 20/21] AUTHORS --- AUTHORS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AUTHORS b/AUTHORS index 4045c6066d..9753c268c6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -14,3 +14,7 @@ Daniel De Matteis - tukuyomi - - Cleanups in quickbuild +Michael Lelli - + - Raspberry Pi video driver + - Linux Raw keyboard input driver + From c5a2fbc6e6fbcad9232c5102306e809af152d71a Mon Sep 17 00:00:00 2001 From: Toad King Date: Tue, 19 Jun 2012 15:01:34 -0400 Subject: [PATCH 21/21] EOL fixes --- gfx/rpi.c | 870 ++++++++++++++++++++--------------------- input/linuxraw_input.c | 612 ++++++++++++++--------------- 2 files changed, 741 insertions(+), 741 deletions(-) diff --git a/gfx/rpi.c b/gfx/rpi.c index b718428c8e..19ea060323 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -1,435 +1,435 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2012 - Hans-Kristian Arntzen - * Copyright (C) 2012 - Michael Lelli - * - * 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 -#include -#include -#include -#include -#include -#include -#include "../libretro.h" -#include "../general.h" -#include "../input/linuxraw_input.h" -#include "../driver.h" - -#ifdef HAVE_FREETYPE -#include "fonts/fonts.h" -#include "../file.h" -#endif - - -typedef struct { - EGLDisplay mDisplay; - EGLSurface mSurface; - EGLContext mContext; - uint32_t mScreenWidth; - uint32_t mScreenHeight; - float mScreenAspect; - bool mKeepAspect; - unsigned mTextureWidth; - unsigned mTextureHeight; - unsigned mRenderWidth; - unsigned mRenderHeight; - unsigned x1, y1, x2, y2; - VGImageFormat mTexType; - VGImage mImage; - VGfloat mTransformMatrix[9]; - VGint scissor[4]; - -#ifdef HAVE_FREETYPE - char *mLastMsg; - uint32_t mFontHeight; - VGFont mFont; - font_renderer_t *mFontRenderer; - bool mFontsOn; - VGuint mMsgLength; - VGuint mGlyphIndices[1024]; - VGPaint mPaintFg; - VGPaint mPaintBg; -#endif -} rpi_t; - -static volatile sig_atomic_t rpi_shutdown = 0; - -static void rpi_kill(int sig) -{ - (void)sig; - rpi_shutdown = 1; -} - -static void rpi_set_nonblock_state(void *data, bool state) -{ - rpi_t *rpi = (rpi_t*)data; - eglSwapInterval(rpi->mDisplay, state ? 0 : 1); -} - -static void *rpi_init(const video_info_t *video, const input_driver_t **input, void **input_data) -{ - int32_t success; - EGLBoolean result; - EGLint num_config; - rpi_t *rpi = (rpi_t*)calloc(1, sizeof(rpi_t)); - *input = NULL; - - static EGL_DISPMANX_WINDOW_T nativewindow; - - DISPMANX_ELEMENT_HANDLE_T dispman_element; - DISPMANX_DISPLAY_HANDLE_T dispman_display; - DISPMANX_UPDATE_HANDLE_T dispman_update; - DISPMANX_MODEINFO_T dispman_modeinfo; - VC_RECT_T dst_rect; - VC_RECT_T src_rect; - - static const EGLint attribute_list[] = - { - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_NONE - }; - - EGLConfig config; - - bcm_host_init(); - - // get an EGL display connection - rpi->mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - rarch_assert(rpi->mDisplay != EGL_NO_DISPLAY); - - // initialize the EGL display connection - result = eglInitialize(rpi->mDisplay, NULL, NULL); - rarch_assert(result != EGL_FALSE); - eglBindAPI(EGL_OPENVG_API); - - // get an appropriate EGL frame buffer configuration - result = eglChooseConfig(rpi->mDisplay, attribute_list, &config, 1, &num_config); - rarch_assert(result != EGL_FALSE); - - // create an EGL rendering context - rpi->mContext = eglCreateContext(rpi->mDisplay, config, EGL_NO_CONTEXT, NULL); - rarch_assert(rpi->mContext != EGL_NO_CONTEXT); - - // create an EGL window surface - success = graphics_get_display_size(0 /* LCD */, &rpi->mScreenWidth, &rpi->mScreenHeight); - rarch_assert(success >= 0); - - dst_rect.x = 0; - dst_rect.y = 0; - dst_rect.width = rpi->mScreenWidth; - dst_rect.height = rpi->mScreenHeight; - - src_rect.x = 0; - src_rect.y = 0; - src_rect.width = rpi->mScreenWidth << 16; - src_rect.height = rpi->mScreenHeight << 16; - - dispman_display = vc_dispmanx_display_open(0 /* LCD */); - vc_dispmanx_display_get_info(dispman_display, &dispman_modeinfo); - dispman_update = vc_dispmanx_update_start(0); - - dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display, - 0/*layer*/, &dst_rect, 0/*src*/, - &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, DISPMANX_NO_ROTATE); - - nativewindow.element = dispman_element; - nativewindow.width = rpi->mScreenWidth; - nativewindow.height = rpi->mScreenHeight; - vc_dispmanx_update_submit_sync(dispman_update); - - rpi->mSurface = eglCreateWindowSurface(rpi->mDisplay, config, &nativewindow, NULL); - rarch_assert(rpi->mSurface != EGL_NO_SURFACE); - - // connect the context to the surface - result = eglMakeCurrent(rpi->mDisplay, rpi->mSurface, rpi->mSurface, rpi->mContext); - rarch_assert(result != EGL_FALSE); - - rpi->mTexType = video->rgb32 ? VG_sABGR_8888 : VG_sARGB_1555; - rpi->mKeepAspect = video->force_aspect; - - // check for SD televisions: they should always be 4:3 - if (dispman_modeinfo.width == 720 && (dispman_modeinfo.height == 480 || dispman_modeinfo.height == 576)) - rpi->mScreenAspect = 4.0f / 3.0f; - else - rpi->mScreenAspect = (float) dispman_modeinfo.width / dispman_modeinfo.height; - - VGfloat clearColor[4] = {0, 0, 0, 1}; - vgSetfv(VG_CLEAR_COLOR, 4, clearColor); - - rpi->mTextureWidth = rpi->mTextureHeight = video->input_scale * RARCH_SCALE_BASE; - // We can't use the native format because there's no sXRGB_1555 type and - // emulation cores can send 0 in the top bit. We lose some speed on - // conversion but I doubt it has any real affect, since we are only drawing - // one image at the end of the day. Still keep the alpha channel for ABGR. - rpi->mImage = vgCreateImage(video->rgb32 ? VG_sABGR_8888 : VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, video->smooth ? VG_IMAGE_QUALITY_BETTER : VG_IMAGE_QUALITY_NONANTIALIASED); - rpi_set_nonblock_state(rpi, !video->vsync); - - linuxraw_input_t *linuxraw_input = (linuxraw_input_t *)input_linuxraw.init(); - if (linuxraw_input) - { - *input = (const input_driver_t *)&input_linuxraw; - *input_data = linuxraw_input; - } - -#ifdef HAVE_FREETYPE - if (g_settings.video.font_enable) - { - rpi->mFont = vgCreateFont(0); - rpi->mFontHeight = g_settings.video.font_size * (g_settings.video.font_scale ? (float) rpi->mScreenWidth / 1280.0f : 1.0f); - - const char *path = g_settings.video.font_path; - if (!*path || !path_file_exists(path)) - path = font_renderer_get_default_font(); - - rpi->mFontRenderer = font_renderer_new(path, rpi->mFontHeight); - - if (rpi->mFont != VG_INVALID_HANDLE && rpi->mFontRenderer) - { - rpi->mFontsOn = true; - - rpi->mPaintFg = vgCreatePaint(); - rpi->mPaintBg = vgCreatePaint(); - VGfloat paintFg[] = { g_settings.video.msg_color_r, g_settings.video.msg_color_g, g_settings.video.msg_color_b, 1.0f }; - VGfloat paintBg[] = { g_settings.video.msg_color_r / 2.0f, g_settings.video.msg_color_g / 2.0f, g_settings.video.msg_color_b / 2.0f, 0.5f }; - - vgSetParameteri(rpi->mPaintFg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); - vgSetParameterfv(rpi->mPaintFg, VG_PAINT_COLOR, 4, paintFg); - - vgSetParameteri(rpi->mPaintBg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); - vgSetParameterfv(rpi->mPaintBg, VG_PAINT_COLOR, 4, paintBg); - } - } -#endif - - struct sigaction sa; - sa.sa_handler = rpi_kill; - sa.sa_flags = SA_RESTART; - sigemptyset(&sa.sa_mask); - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - - return rpi; -} - -static void rpi_free(void *data) -{ - rpi_t *rpi = (rpi_t*)data; - - vgDestroyImage(rpi->mImage); - -#ifdef HAVE_FREETYPE - if (rpi->mFontsOn) - { - vgDestroyFont(rpi->mFont); - font_renderer_free(rpi->mFontRenderer); - vgDestroyPaint(rpi->mPaintFg); - vgDestroyPaint(rpi->mPaintBg); - } -#endif - - // Release EGL resources - eglMakeCurrent(rpi->mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroySurface(rpi->mDisplay, rpi->mSurface); - eglDestroyContext(rpi->mDisplay, rpi->mContext); - eglTerminate(rpi->mDisplay); - - free(rpi); -} - -#ifdef HAVE_FREETYPE - -static void rpi_render_message(rpi_t *rpi, const char *msg) -{ - free(rpi->mLastMsg); - rpi->mLastMsg = strdup(msg); - - if(rpi->mMsgLength) - { - while (--rpi->mMsgLength) - vgClearGlyph(rpi->mFont, rpi->mMsgLength); - - vgClearGlyph(rpi->mFont, 0); - } - - struct font_output_list out; - font_renderer_msg(rpi->mFontRenderer, msg, &out); - struct font_output *head = out.head; - - while (head) - { - if (rpi->mMsgLength >= 1024) - break; - - VGfloat origin[2], escapement[2]; - VGImage img; - - escapement[0] = (VGfloat) (head->advance_x); - escapement[1] = (VGfloat) (head->advance_y); - origin[0] = (VGfloat) (-head->char_off_x); - origin[1] = (VGfloat) (head->char_off_y); - - img = vgCreateImage(VG_A_8, head->width, head->height, VG_IMAGE_QUALITY_NONANTIALIASED); - - // flip it - for (unsigned i = 0; i < head->height; i++) - vgImageSubData(img, head->output + head->pitch * i, head->pitch, VG_A_8, 0, head->height - i - 1, head->width, 1); - - vgSetGlyphToImage(rpi->mFont, rpi->mMsgLength, img, origin, escapement); - vgDestroyImage(img); - - rpi->mMsgLength++; - head = head->next; - } - - font_renderer_free_output(&out); - - for (unsigned i = 0; i < rpi->mMsgLength; i++) - rpi->mGlyphIndices[i] = i; -} - -static void rpi_draw_message(rpi_t *rpi, const char *msg) -{ - if (!rpi->mLastMsg || strcmp(rpi->mLastMsg, msg)) - rpi_render_message(rpi, msg); - - vgSeti(VG_SCISSORING, VG_FALSE); - vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL); - - VGfloat origins[] = { rpi->mScreenWidth * g_settings.video.msg_pos_x - 2.0f, rpi->mScreenHeight * g_settings.video.msg_pos_y - 2.0f }; - vgSetfv(VG_GLYPH_ORIGIN, 2, origins); - vgSetPaint(rpi->mPaintBg, VG_FILL_PATH); - vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE); - origins[0] += 2.0f; - origins[1] += 2.0f; - vgSetfv(VG_GLYPH_ORIGIN, 2, origins); - vgSetPaint(rpi->mPaintFg, VG_FILL_PATH); - vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE); - - vgSeti(VG_SCISSORING, VG_TRUE); - vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL); -} - -#endif - -static void rpi_calculate_quad(rpi_t *rpi) -{ - // set viewport for aspect ratio, taken from the OpenGL driver - if (rpi->mKeepAspect) - { - float desired_aspect = g_settings.video.aspect_ratio; - - // If the aspect ratios of screen and desired aspect ratio are sufficiently equal (floating point stuff), - // assume they are actually equal. - if (fabs(rpi->mScreenAspect - desired_aspect) < 0.0001) - { - rpi->x1 = 0; - rpi->y1 = 0; - rpi->x2 = rpi->mScreenWidth; - rpi->y2 = rpi->mScreenHeight; - } - else if (rpi->mScreenAspect > desired_aspect) - { - float delta = (desired_aspect / rpi->mScreenAspect - 1.0) / 2.0 + 0.5; - rpi->x1 = rpi->mScreenWidth * (0.5 - delta); - rpi->y1 = 0; - rpi->x2 = 2.0 * rpi->mScreenWidth * delta + rpi->x1; - rpi->y2 = rpi->mScreenHeight + rpi->y1; - } - else - { - float delta = (rpi->mScreenAspect / desired_aspect - 1.0) / 2.0 + 0.5; - rpi->x1 = 0; - rpi->y1 = rpi->mScreenHeight * (0.5 - delta); - rpi->x2 = rpi->mScreenWidth + rpi->x1; - rpi->y2 = 2.0 * rpi->mScreenHeight * delta + rpi->y1; - } - } - else - { - rpi->x1 = 0; - rpi->y1 = 0; - rpi->x2 = rpi->mScreenWidth; - rpi->y2 = rpi->mScreenHeight; - } - - rpi->scissor[0] = rpi->x1; - rpi->scissor[1] = rpi->y1; - rpi->scissor[2] = rpi->x2 - rpi->x1; - rpi->scissor[3] = rpi->y2 - rpi->y1; - - vgSetiv(VG_SCISSOR_RECTS, 4, rpi->scissor); -} - -static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) -{ - rpi_t *rpi = (rpi_t*)data; - - if (width != rpi->mRenderWidth || height != rpi->mRenderHeight) - { - rpi->mRenderWidth = width; - rpi->mRenderHeight = height; - rpi_calculate_quad(rpi); - vguComputeWarpQuadToQuad( - rpi->x1, rpi->y1, rpi->x2, rpi->y1, rpi->x2, rpi->y2, rpi->x1, rpi->y2, - // needs to be flipped, Khronos loves their bottom-left origin - 0, height, width, height, width, 0, 0, 0, - rpi->mTransformMatrix); - vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); - vgLoadMatrix(rpi->mTransformMatrix); - } - vgSeti(VG_SCISSORING, VG_FALSE); - vgClear(0, 0, rpi->mScreenWidth, rpi->mScreenHeight); - vgSeti(VG_SCISSORING, VG_TRUE); - - vgImageSubData(rpi->mImage, frame, pitch, rpi->mTexType, 0, 0, width, height); - vgDrawImage(rpi->mImage); - -#ifdef HAVE_FREETYPE - if (msg && rpi->mFontsOn) - rpi_draw_message(rpi, msg); -#else - (void)msg; -#endif - - eglSwapBuffers(rpi->mDisplay, rpi->mSurface); - - return true; -} - -static bool rpi_alive(void *data) -{ - (void)data; - return !rpi_shutdown; -} - -static bool rpi_focus(void *data) -{ - (void)data; - return true; -} - -const video_driver_t video_rpi = { - rpi_init, - rpi_frame, - rpi_set_nonblock_state, - rpi_alive, - rpi_focus, - NULL, - rpi_free, - "rpi" -}; +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2012 - Michael Lelli + * + * 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 +#include +#include +#include +#include +#include +#include +#include "../libretro.h" +#include "../general.h" +#include "../input/linuxraw_input.h" +#include "../driver.h" + +#ifdef HAVE_FREETYPE +#include "fonts/fonts.h" +#include "../file.h" +#endif + + +typedef struct { + EGLDisplay mDisplay; + EGLSurface mSurface; + EGLContext mContext; + uint32_t mScreenWidth; + uint32_t mScreenHeight; + float mScreenAspect; + bool mKeepAspect; + unsigned mTextureWidth; + unsigned mTextureHeight; + unsigned mRenderWidth; + unsigned mRenderHeight; + unsigned x1, y1, x2, y2; + VGImageFormat mTexType; + VGImage mImage; + VGfloat mTransformMatrix[9]; + VGint scissor[4]; + +#ifdef HAVE_FREETYPE + char *mLastMsg; + uint32_t mFontHeight; + VGFont mFont; + font_renderer_t *mFontRenderer; + bool mFontsOn; + VGuint mMsgLength; + VGuint mGlyphIndices[1024]; + VGPaint mPaintFg; + VGPaint mPaintBg; +#endif +} rpi_t; + +static volatile sig_atomic_t rpi_shutdown = 0; + +static void rpi_kill(int sig) +{ + (void)sig; + rpi_shutdown = 1; +} + +static void rpi_set_nonblock_state(void *data, bool state) +{ + rpi_t *rpi = (rpi_t*)data; + eglSwapInterval(rpi->mDisplay, state ? 0 : 1); +} + +static void *rpi_init(const video_info_t *video, const input_driver_t **input, void **input_data) +{ + int32_t success; + EGLBoolean result; + EGLint num_config; + rpi_t *rpi = (rpi_t*)calloc(1, sizeof(rpi_t)); + *input = NULL; + + static EGL_DISPMANX_WINDOW_T nativewindow; + + DISPMANX_ELEMENT_HANDLE_T dispman_element; + DISPMANX_DISPLAY_HANDLE_T dispman_display; + DISPMANX_UPDATE_HANDLE_T dispman_update; + DISPMANX_MODEINFO_T dispman_modeinfo; + VC_RECT_T dst_rect; + VC_RECT_T src_rect; + + static const EGLint attribute_list[] = + { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_NONE + }; + + EGLConfig config; + + bcm_host_init(); + + // get an EGL display connection + rpi->mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + rarch_assert(rpi->mDisplay != EGL_NO_DISPLAY); + + // initialize the EGL display connection + result = eglInitialize(rpi->mDisplay, NULL, NULL); + rarch_assert(result != EGL_FALSE); + eglBindAPI(EGL_OPENVG_API); + + // get an appropriate EGL frame buffer configuration + result = eglChooseConfig(rpi->mDisplay, attribute_list, &config, 1, &num_config); + rarch_assert(result != EGL_FALSE); + + // create an EGL rendering context + rpi->mContext = eglCreateContext(rpi->mDisplay, config, EGL_NO_CONTEXT, NULL); + rarch_assert(rpi->mContext != EGL_NO_CONTEXT); + + // create an EGL window surface + success = graphics_get_display_size(0 /* LCD */, &rpi->mScreenWidth, &rpi->mScreenHeight); + rarch_assert(success >= 0); + + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.width = rpi->mScreenWidth; + dst_rect.height = rpi->mScreenHeight; + + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = rpi->mScreenWidth << 16; + src_rect.height = rpi->mScreenHeight << 16; + + dispman_display = vc_dispmanx_display_open(0 /* LCD */); + vc_dispmanx_display_get_info(dispman_display, &dispman_modeinfo); + dispman_update = vc_dispmanx_update_start(0); + + dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display, + 0/*layer*/, &dst_rect, 0/*src*/, + &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, DISPMANX_NO_ROTATE); + + nativewindow.element = dispman_element; + nativewindow.width = rpi->mScreenWidth; + nativewindow.height = rpi->mScreenHeight; + vc_dispmanx_update_submit_sync(dispman_update); + + rpi->mSurface = eglCreateWindowSurface(rpi->mDisplay, config, &nativewindow, NULL); + rarch_assert(rpi->mSurface != EGL_NO_SURFACE); + + // connect the context to the surface + result = eglMakeCurrent(rpi->mDisplay, rpi->mSurface, rpi->mSurface, rpi->mContext); + rarch_assert(result != EGL_FALSE); + + rpi->mTexType = video->rgb32 ? VG_sABGR_8888 : VG_sARGB_1555; + rpi->mKeepAspect = video->force_aspect; + + // check for SD televisions: they should always be 4:3 + if (dispman_modeinfo.width == 720 && (dispman_modeinfo.height == 480 || dispman_modeinfo.height == 576)) + rpi->mScreenAspect = 4.0f / 3.0f; + else + rpi->mScreenAspect = (float) dispman_modeinfo.width / dispman_modeinfo.height; + + VGfloat clearColor[4] = {0, 0, 0, 1}; + vgSetfv(VG_CLEAR_COLOR, 4, clearColor); + + rpi->mTextureWidth = rpi->mTextureHeight = video->input_scale * RARCH_SCALE_BASE; + // We can't use the native format because there's no sXRGB_1555 type and + // emulation cores can send 0 in the top bit. We lose some speed on + // conversion but I doubt it has any real affect, since we are only drawing + // one image at the end of the day. Still keep the alpha channel for ABGR. + rpi->mImage = vgCreateImage(video->rgb32 ? VG_sABGR_8888 : VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, video->smooth ? VG_IMAGE_QUALITY_BETTER : VG_IMAGE_QUALITY_NONANTIALIASED); + rpi_set_nonblock_state(rpi, !video->vsync); + + linuxraw_input_t *linuxraw_input = (linuxraw_input_t *)input_linuxraw.init(); + if (linuxraw_input) + { + *input = (const input_driver_t *)&input_linuxraw; + *input_data = linuxraw_input; + } + +#ifdef HAVE_FREETYPE + if (g_settings.video.font_enable) + { + rpi->mFont = vgCreateFont(0); + rpi->mFontHeight = g_settings.video.font_size * (g_settings.video.font_scale ? (float) rpi->mScreenWidth / 1280.0f : 1.0f); + + const char *path = g_settings.video.font_path; + if (!*path || !path_file_exists(path)) + path = font_renderer_get_default_font(); + + rpi->mFontRenderer = font_renderer_new(path, rpi->mFontHeight); + + if (rpi->mFont != VG_INVALID_HANDLE && rpi->mFontRenderer) + { + rpi->mFontsOn = true; + + rpi->mPaintFg = vgCreatePaint(); + rpi->mPaintBg = vgCreatePaint(); + VGfloat paintFg[] = { g_settings.video.msg_color_r, g_settings.video.msg_color_g, g_settings.video.msg_color_b, 1.0f }; + VGfloat paintBg[] = { g_settings.video.msg_color_r / 2.0f, g_settings.video.msg_color_g / 2.0f, g_settings.video.msg_color_b / 2.0f, 0.5f }; + + vgSetParameteri(rpi->mPaintFg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(rpi->mPaintFg, VG_PAINT_COLOR, 4, paintFg); + + vgSetParameteri(rpi->mPaintBg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(rpi->mPaintBg, VG_PAINT_COLOR, 4, paintBg); + } + } +#endif + + struct sigaction sa; + sa.sa_handler = rpi_kill; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + return rpi; +} + +static void rpi_free(void *data) +{ + rpi_t *rpi = (rpi_t*)data; + + vgDestroyImage(rpi->mImage); + +#ifdef HAVE_FREETYPE + if (rpi->mFontsOn) + { + vgDestroyFont(rpi->mFont); + font_renderer_free(rpi->mFontRenderer); + vgDestroyPaint(rpi->mPaintFg); + vgDestroyPaint(rpi->mPaintBg); + } +#endif + + // Release EGL resources + eglMakeCurrent(rpi->mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(rpi->mDisplay, rpi->mSurface); + eglDestroyContext(rpi->mDisplay, rpi->mContext); + eglTerminate(rpi->mDisplay); + + free(rpi); +} + +#ifdef HAVE_FREETYPE + +static void rpi_render_message(rpi_t *rpi, const char *msg) +{ + free(rpi->mLastMsg); + rpi->mLastMsg = strdup(msg); + + if(rpi->mMsgLength) + { + while (--rpi->mMsgLength) + vgClearGlyph(rpi->mFont, rpi->mMsgLength); + + vgClearGlyph(rpi->mFont, 0); + } + + struct font_output_list out; + font_renderer_msg(rpi->mFontRenderer, msg, &out); + struct font_output *head = out.head; + + while (head) + { + if (rpi->mMsgLength >= 1024) + break; + + VGfloat origin[2], escapement[2]; + VGImage img; + + escapement[0] = (VGfloat) (head->advance_x); + escapement[1] = (VGfloat) (head->advance_y); + origin[0] = (VGfloat) (-head->char_off_x); + origin[1] = (VGfloat) (head->char_off_y); + + img = vgCreateImage(VG_A_8, head->width, head->height, VG_IMAGE_QUALITY_NONANTIALIASED); + + // flip it + for (unsigned i = 0; i < head->height; i++) + vgImageSubData(img, head->output + head->pitch * i, head->pitch, VG_A_8, 0, head->height - i - 1, head->width, 1); + + vgSetGlyphToImage(rpi->mFont, rpi->mMsgLength, img, origin, escapement); + vgDestroyImage(img); + + rpi->mMsgLength++; + head = head->next; + } + + font_renderer_free_output(&out); + + for (unsigned i = 0; i < rpi->mMsgLength; i++) + rpi->mGlyphIndices[i] = i; +} + +static void rpi_draw_message(rpi_t *rpi, const char *msg) +{ + if (!rpi->mLastMsg || strcmp(rpi->mLastMsg, msg)) + rpi_render_message(rpi, msg); + + vgSeti(VG_SCISSORING, VG_FALSE); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL); + + VGfloat origins[] = { rpi->mScreenWidth * g_settings.video.msg_pos_x - 2.0f, rpi->mScreenHeight * g_settings.video.msg_pos_y - 2.0f }; + vgSetfv(VG_GLYPH_ORIGIN, 2, origins); + vgSetPaint(rpi->mPaintBg, VG_FILL_PATH); + vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE); + origins[0] += 2.0f; + origins[1] += 2.0f; + vgSetfv(VG_GLYPH_ORIGIN, 2, origins); + vgSetPaint(rpi->mPaintFg, VG_FILL_PATH); + vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE); + + vgSeti(VG_SCISSORING, VG_TRUE); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL); +} + +#endif + +static void rpi_calculate_quad(rpi_t *rpi) +{ + // set viewport for aspect ratio, taken from the OpenGL driver + if (rpi->mKeepAspect) + { + float desired_aspect = g_settings.video.aspect_ratio; + + // If the aspect ratios of screen and desired aspect ratio are sufficiently equal (floating point stuff), + // assume they are actually equal. + if (fabs(rpi->mScreenAspect - desired_aspect) < 0.0001) + { + rpi->x1 = 0; + rpi->y1 = 0; + rpi->x2 = rpi->mScreenWidth; + rpi->y2 = rpi->mScreenHeight; + } + else if (rpi->mScreenAspect > desired_aspect) + { + float delta = (desired_aspect / rpi->mScreenAspect - 1.0) / 2.0 + 0.5; + rpi->x1 = rpi->mScreenWidth * (0.5 - delta); + rpi->y1 = 0; + rpi->x2 = 2.0 * rpi->mScreenWidth * delta + rpi->x1; + rpi->y2 = rpi->mScreenHeight + rpi->y1; + } + else + { + float delta = (rpi->mScreenAspect / desired_aspect - 1.0) / 2.0 + 0.5; + rpi->x1 = 0; + rpi->y1 = rpi->mScreenHeight * (0.5 - delta); + rpi->x2 = rpi->mScreenWidth + rpi->x1; + rpi->y2 = 2.0 * rpi->mScreenHeight * delta + rpi->y1; + } + } + else + { + rpi->x1 = 0; + rpi->y1 = 0; + rpi->x2 = rpi->mScreenWidth; + rpi->y2 = rpi->mScreenHeight; + } + + rpi->scissor[0] = rpi->x1; + rpi->scissor[1] = rpi->y1; + rpi->scissor[2] = rpi->x2 - rpi->x1; + rpi->scissor[3] = rpi->y2 - rpi->y1; + + vgSetiv(VG_SCISSOR_RECTS, 4, rpi->scissor); +} + +static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) +{ + rpi_t *rpi = (rpi_t*)data; + + if (width != rpi->mRenderWidth || height != rpi->mRenderHeight) + { + rpi->mRenderWidth = width; + rpi->mRenderHeight = height; + rpi_calculate_quad(rpi); + vguComputeWarpQuadToQuad( + rpi->x1, rpi->y1, rpi->x2, rpi->y1, rpi->x2, rpi->y2, rpi->x1, rpi->y2, + // needs to be flipped, Khronos loves their bottom-left origin + 0, height, width, height, width, 0, 0, 0, + rpi->mTransformMatrix); + vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); + vgLoadMatrix(rpi->mTransformMatrix); + } + vgSeti(VG_SCISSORING, VG_FALSE); + vgClear(0, 0, rpi->mScreenWidth, rpi->mScreenHeight); + vgSeti(VG_SCISSORING, VG_TRUE); + + vgImageSubData(rpi->mImage, frame, pitch, rpi->mTexType, 0, 0, width, height); + vgDrawImage(rpi->mImage); + +#ifdef HAVE_FREETYPE + if (msg && rpi->mFontsOn) + rpi_draw_message(rpi, msg); +#else + (void)msg; +#endif + + eglSwapBuffers(rpi->mDisplay, rpi->mSurface); + + return true; +} + +static bool rpi_alive(void *data) +{ + (void)data; + return !rpi_shutdown; +} + +static bool rpi_focus(void *data) +{ + (void)data; + return true; +} + +const video_driver_t video_rpi = { + rpi_init, + rpi_frame, + rpi_set_nonblock_state, + rpi_alive, + rpi_focus, + NULL, + rpi_free, + "rpi" +}; diff --git a/input/linuxraw_input.c b/input/linuxraw_input.c index 97fec4e17e..a0069c3eba 100644 --- a/input/linuxraw_input.c +++ b/input/linuxraw_input.c @@ -1,306 +1,306 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2012 - Hans-Kristian Arntzen - * Copyright (C) 2012 - Michael Lelli - * - * 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 -#include -#include -#include -#include -#include -#include "../general.h" -#include "linuxraw_input.h" -#include "rarch_sdl_input.h" - -static long oldKbmd = 0xFFFF; -static struct termios oldTerm, newTerm; - -struct key_bind -{ - uint8_t x; - enum rarch_key sk; -}; - -static unsigned keysym_lut[SK_LAST]; -static const struct key_bind lut_binds[] = { - { KEY_ESC, SK_ESCAPE }, - { KEY_1, SK_1 }, - { KEY_2, SK_2 }, - { KEY_3, SK_3}, - { KEY_4, SK_4 }, - { KEY_5, SK_5 }, - { KEY_6, SK_6 }, - { KEY_7, SK_7 }, - { KEY_8, SK_8 }, - { KEY_9, SK_9 }, - { KEY_0, SK_0 }, - { KEY_MINUS, SK_MINUS }, - { KEY_EQUAL, SK_EQUALS }, - { KEY_BACKSPACE, SK_BACKSPACE }, - { KEY_TAB, SK_TAB }, - { KEY_Q, SK_q }, - { KEY_W, SK_w }, - { KEY_E, SK_e }, - { KEY_R, SK_r }, - { KEY_T, SK_t }, - { KEY_Y, SK_y }, - { KEY_U, SK_u }, - { KEY_I, SK_i }, - { KEY_O, SK_o }, - { KEY_P, SK_p }, - { KEY_LEFTBRACE, SK_LEFTBRACKET }, - { KEY_RIGHTBRACE, SK_RIGHTBRACKET }, - { KEY_ENTER, SK_RETURN }, - { KEY_LEFTCTRL, SK_LCTRL }, - { KEY_A, SK_a }, - { KEY_S, SK_s }, - { KEY_D, SK_d }, - { KEY_F, SK_f }, - { KEY_G, SK_g }, - { KEY_H, SK_h }, - { KEY_J, SK_j }, - { KEY_K, SK_k }, - { KEY_L, SK_l }, - { KEY_SEMICOLON, SK_SEMICOLON }, - { KEY_APOSTROPHE, SK_QUOTE }, - { KEY_GRAVE, SK_BACKQUOTE }, - { KEY_LEFTSHIFT, SK_LSHIFT }, - { KEY_BACKSLASH, SK_BACKSLASH }, - { KEY_Z, SK_z }, - { KEY_X, SK_x }, - { KEY_C, SK_c }, - { KEY_V, SK_v }, - { KEY_B, SK_b }, - { KEY_N, SK_n }, - { KEY_M, SK_m }, - { KEY_COMMA, SK_COMMA }, - { KEY_DOT, SK_PERIOD }, - { KEY_SLASH, SK_SLASH }, - { KEY_RIGHTSHIFT, SK_RSHIFT }, - { KEY_KPASTERISK, SK_KP_MULTIPLY }, - { KEY_LEFTALT, SK_LALT }, - { KEY_SPACE, SK_SPACE }, - { KEY_CAPSLOCK, SK_CAPSLOCK }, - { KEY_F1, SK_F1 }, - { KEY_F2, SK_F2 }, - { KEY_F3, SK_F3 }, - { KEY_F4, SK_F4 }, - { KEY_F5, SK_F5 }, - { KEY_F6, SK_F6 }, - { KEY_F7, SK_F7 }, - { KEY_F8, SK_F8 }, - { KEY_F9, SK_F9 }, - { KEY_F10, SK_F10 }, - { KEY_NUMLOCK, SK_NUMLOCK }, - { KEY_SCROLLLOCK, SK_SCROLLOCK }, - { KEY_KP7, SK_KP7 }, - { KEY_KP8, SK_KP8 }, - { KEY_KP9, SK_KP9 }, - { KEY_KPMINUS, SK_KP_MINUS }, - { KEY_KP4, SK_KP4 }, - { KEY_KP5, SK_KP5 }, - { KEY_KP6, SK_KP6 }, - { KEY_KPPLUS, SK_KP_PLUS }, - { KEY_KP1, SK_KP1 }, - { KEY_KP2, SK_KP2 }, - { KEY_KP3, SK_KP3 }, - { KEY_KP0, SK_KP0 }, - { KEY_KPDOT, SK_KP_PERIOD }, - - { KEY_F11, SK_F11 }, - { KEY_F12, SK_F12 }, - - { KEY_KPENTER, SK_KP_ENTER }, - { KEY_RIGHTCTRL, SK_RCTRL }, - { KEY_KPSLASH, SK_KP_DIVIDE }, - { KEY_SYSRQ, SK_PRINT }, - { KEY_RIGHTALT, SK_RALT }, - - { KEY_HOME, SK_HOME }, - { KEY_UP, SK_UP }, - { KEY_PAGEUP, SK_PAGEUP }, - { KEY_LEFT, SK_LEFT }, - { KEY_RIGHT, SK_RIGHT }, - { KEY_END, SK_END }, - { KEY_DOWN, SK_DOWN }, - { KEY_PAGEDOWN, SK_PAGEDOWN }, - { KEY_INSERT, SK_INSERT }, - { KEY_DELETE, SK_DELETE }, - - { KEY_PAUSE, SK_PAUSE }, -}; - -static void init_lut(void) -{ - memset(keysym_lut, 0, sizeof(keysym_lut)); - for (unsigned i = 0; i < sizeof(lut_binds) / sizeof(lut_binds[0]); i++) - keysym_lut[lut_binds[i].sk] = lut_binds[i].x; -} - -static void linuxraw_resetKbmd() -{ - if (oldKbmd != 0xFFFF) - { - ioctl(0, KDSKBMODE, oldKbmd); - tcsetattr(0, TCSAFLUSH, &oldTerm); - oldKbmd = 0xFFFF; - } -} - -static void linuxraw_exitGracefully(int sig) -{ - linuxraw_resetKbmd(); - kill(getpid(), sig); -} - -static void *linuxraw_input_init(void) -{ - // only work on terminals - if (!isatty(0)) - return NULL; - - linuxraw_input_t *linuxraw = (linuxraw_input_t*)calloc(1, sizeof(*linuxraw)); - if (!linuxraw) - return NULL; - - if (oldKbmd == 0xFFFF) - { - tcgetattr(0, &oldTerm); - newTerm = oldTerm; - newTerm.c_lflag &= ~(ECHO | ICANON | ISIG); - newTerm.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); - newTerm.c_cc[VMIN] = 0; - newTerm.c_cc[VTIME] = 0; - - if (ioctl(0, KDGKBMODE, &oldKbmd) != 0) - return NULL; - } - - tcsetattr(0, TCSAFLUSH, &newTerm); - - if (ioctl(0, KDSKBMODE, K_MEDIUMRAW) != 0) - { - linuxraw_resetKbmd(); - return NULL; - } - - struct sigaction sa; - sa.sa_handler = linuxraw_exitGracefully; - sa.sa_flags = SA_RESTART | SA_RESETHAND; - sigemptyset(&sa.sa_mask); - // trap some standard termination codes so we can restore the keyboard before we lose control - sigaction(SIGABRT, &sa, NULL); - sigaction(SIGBUS, &sa, NULL); - sigaction(SIGFPE, &sa, NULL); - sigaction(SIGILL, &sa, NULL); - sigaction(SIGQUIT, &sa, NULL); - sigaction(SIGSEGV, &sa, NULL); - - atexit(linuxraw_resetKbmd); - - linuxraw->sdl = (sdl_input_t*)input_sdl.init(); - if (!linuxraw->sdl) - { - linuxraw_resetKbmd(); - free(linuxraw); - return NULL; - } - - init_lut(); - - linuxraw->sdl->use_keyboard = false; - return linuxraw; -} - -static bool linuxraw_key_pressed(linuxraw_input_t *linuxraw, int key) -{ - return linuxraw->state[keysym_lut[key]]; -} - -static bool linuxraw_is_pressed(linuxraw_input_t *linuxraw, const struct snes_keybind *binds, unsigned id) -{ - if (id < RARCH_BIND_LIST_END) - { - const struct snes_keybind *bind = &binds[id]; - return bind->valid && linuxraw_key_pressed(linuxraw, binds[id].key); - } - else - return false; -} - -static bool linuxraw_bind_button_pressed(void *data, int key) -{ - linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; - return linuxraw_is_pressed(linuxraw, g_settings.input.binds[0], key) || - input_sdl.key_pressed(linuxraw->sdl, key); -} - -static int16_t linuxraw_input_state(void *data, const struct snes_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id) -{ - linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; - - switch (device) - { - case RETRO_DEVICE_JOYPAD: - return linuxraw_is_pressed(linuxraw, binds[port], id) || - input_sdl.input_state(linuxraw->sdl, binds, port, device, index, id); - - default: - return 0; - } -} - -static void linuxraw_input_free(void *data) -{ - linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; - input_sdl.free(linuxraw->sdl); - linuxraw_resetKbmd(); - free(data); -} - -static void linuxraw_input_poll(void *data) -{ - linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; - uint8_t c; - uint16_t t; - - while (read(0, &c, 1) > 0) - { - bool pressed = !(c & 0x80); - c &= ~0x80; - - // ignore extended scancodes - if (!c) - read(0, &t, 2); - else - linuxraw->state[c] = pressed; - } - - if (linuxraw->state[KEY_C] && (linuxraw->state[KEY_LEFTCTRL] || linuxraw->state[KEY_RIGHTCTRL])) - kill(getpid(), SIGINT); - - input_sdl.poll(linuxraw->sdl); -} - -const input_driver_t input_linuxraw = { - linuxraw_input_init, - linuxraw_input_poll, - linuxraw_input_state, - linuxraw_bind_button_pressed, - linuxraw_input_free, - "linuxraw" -}; +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2012 - Michael Lelli + * + * 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 +#include +#include +#include +#include +#include +#include "../general.h" +#include "linuxraw_input.h" +#include "rarch_sdl_input.h" + +static long oldKbmd = 0xFFFF; +static struct termios oldTerm, newTerm; + +struct key_bind +{ + uint8_t x; + enum rarch_key sk; +}; + +static unsigned keysym_lut[SK_LAST]; +static const struct key_bind lut_binds[] = { + { KEY_ESC, SK_ESCAPE }, + { KEY_1, SK_1 }, + { KEY_2, SK_2 }, + { KEY_3, SK_3}, + { KEY_4, SK_4 }, + { KEY_5, SK_5 }, + { KEY_6, SK_6 }, + { KEY_7, SK_7 }, + { KEY_8, SK_8 }, + { KEY_9, SK_9 }, + { KEY_0, SK_0 }, + { KEY_MINUS, SK_MINUS }, + { KEY_EQUAL, SK_EQUALS }, + { KEY_BACKSPACE, SK_BACKSPACE }, + { KEY_TAB, SK_TAB }, + { KEY_Q, SK_q }, + { KEY_W, SK_w }, + { KEY_E, SK_e }, + { KEY_R, SK_r }, + { KEY_T, SK_t }, + { KEY_Y, SK_y }, + { KEY_U, SK_u }, + { KEY_I, SK_i }, + { KEY_O, SK_o }, + { KEY_P, SK_p }, + { KEY_LEFTBRACE, SK_LEFTBRACKET }, + { KEY_RIGHTBRACE, SK_RIGHTBRACKET }, + { KEY_ENTER, SK_RETURN }, + { KEY_LEFTCTRL, SK_LCTRL }, + { KEY_A, SK_a }, + { KEY_S, SK_s }, + { KEY_D, SK_d }, + { KEY_F, SK_f }, + { KEY_G, SK_g }, + { KEY_H, SK_h }, + { KEY_J, SK_j }, + { KEY_K, SK_k }, + { KEY_L, SK_l }, + { KEY_SEMICOLON, SK_SEMICOLON }, + { KEY_APOSTROPHE, SK_QUOTE }, + { KEY_GRAVE, SK_BACKQUOTE }, + { KEY_LEFTSHIFT, SK_LSHIFT }, + { KEY_BACKSLASH, SK_BACKSLASH }, + { KEY_Z, SK_z }, + { KEY_X, SK_x }, + { KEY_C, SK_c }, + { KEY_V, SK_v }, + { KEY_B, SK_b }, + { KEY_N, SK_n }, + { KEY_M, SK_m }, + { KEY_COMMA, SK_COMMA }, + { KEY_DOT, SK_PERIOD }, + { KEY_SLASH, SK_SLASH }, + { KEY_RIGHTSHIFT, SK_RSHIFT }, + { KEY_KPASTERISK, SK_KP_MULTIPLY }, + { KEY_LEFTALT, SK_LALT }, + { KEY_SPACE, SK_SPACE }, + { KEY_CAPSLOCK, SK_CAPSLOCK }, + { KEY_F1, SK_F1 }, + { KEY_F2, SK_F2 }, + { KEY_F3, SK_F3 }, + { KEY_F4, SK_F4 }, + { KEY_F5, SK_F5 }, + { KEY_F6, SK_F6 }, + { KEY_F7, SK_F7 }, + { KEY_F8, SK_F8 }, + { KEY_F9, SK_F9 }, + { KEY_F10, SK_F10 }, + { KEY_NUMLOCK, SK_NUMLOCK }, + { KEY_SCROLLLOCK, SK_SCROLLOCK }, + { KEY_KP7, SK_KP7 }, + { KEY_KP8, SK_KP8 }, + { KEY_KP9, SK_KP9 }, + { KEY_KPMINUS, SK_KP_MINUS }, + { KEY_KP4, SK_KP4 }, + { KEY_KP5, SK_KP5 }, + { KEY_KP6, SK_KP6 }, + { KEY_KPPLUS, SK_KP_PLUS }, + { KEY_KP1, SK_KP1 }, + { KEY_KP2, SK_KP2 }, + { KEY_KP3, SK_KP3 }, + { KEY_KP0, SK_KP0 }, + { KEY_KPDOT, SK_KP_PERIOD }, + + { KEY_F11, SK_F11 }, + { KEY_F12, SK_F12 }, + + { KEY_KPENTER, SK_KP_ENTER }, + { KEY_RIGHTCTRL, SK_RCTRL }, + { KEY_KPSLASH, SK_KP_DIVIDE }, + { KEY_SYSRQ, SK_PRINT }, + { KEY_RIGHTALT, SK_RALT }, + + { KEY_HOME, SK_HOME }, + { KEY_UP, SK_UP }, + { KEY_PAGEUP, SK_PAGEUP }, + { KEY_LEFT, SK_LEFT }, + { KEY_RIGHT, SK_RIGHT }, + { KEY_END, SK_END }, + { KEY_DOWN, SK_DOWN }, + { KEY_PAGEDOWN, SK_PAGEDOWN }, + { KEY_INSERT, SK_INSERT }, + { KEY_DELETE, SK_DELETE }, + + { KEY_PAUSE, SK_PAUSE }, +}; + +static void init_lut(void) +{ + memset(keysym_lut, 0, sizeof(keysym_lut)); + for (unsigned i = 0; i < sizeof(lut_binds) / sizeof(lut_binds[0]); i++) + keysym_lut[lut_binds[i].sk] = lut_binds[i].x; +} + +static void linuxraw_resetKbmd() +{ + if (oldKbmd != 0xFFFF) + { + ioctl(0, KDSKBMODE, oldKbmd); + tcsetattr(0, TCSAFLUSH, &oldTerm); + oldKbmd = 0xFFFF; + } +} + +static void linuxraw_exitGracefully(int sig) +{ + linuxraw_resetKbmd(); + kill(getpid(), sig); +} + +static void *linuxraw_input_init(void) +{ + // only work on terminals + if (!isatty(0)) + return NULL; + + linuxraw_input_t *linuxraw = (linuxraw_input_t*)calloc(1, sizeof(*linuxraw)); + if (!linuxraw) + return NULL; + + if (oldKbmd == 0xFFFF) + { + tcgetattr(0, &oldTerm); + newTerm = oldTerm; + newTerm.c_lflag &= ~(ECHO | ICANON | ISIG); + newTerm.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); + newTerm.c_cc[VMIN] = 0; + newTerm.c_cc[VTIME] = 0; + + if (ioctl(0, KDGKBMODE, &oldKbmd) != 0) + return NULL; + } + + tcsetattr(0, TCSAFLUSH, &newTerm); + + if (ioctl(0, KDSKBMODE, K_MEDIUMRAW) != 0) + { + linuxraw_resetKbmd(); + return NULL; + } + + struct sigaction sa; + sa.sa_handler = linuxraw_exitGracefully; + sa.sa_flags = SA_RESTART | SA_RESETHAND; + sigemptyset(&sa.sa_mask); + // trap some standard termination codes so we can restore the keyboard before we lose control + sigaction(SIGABRT, &sa, NULL); + sigaction(SIGBUS, &sa, NULL); + sigaction(SIGFPE, &sa, NULL); + sigaction(SIGILL, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGSEGV, &sa, NULL); + + atexit(linuxraw_resetKbmd); + + linuxraw->sdl = (sdl_input_t*)input_sdl.init(); + if (!linuxraw->sdl) + { + linuxraw_resetKbmd(); + free(linuxraw); + return NULL; + } + + init_lut(); + + linuxraw->sdl->use_keyboard = false; + return linuxraw; +} + +static bool linuxraw_key_pressed(linuxraw_input_t *linuxraw, int key) +{ + return linuxraw->state[keysym_lut[key]]; +} + +static bool linuxraw_is_pressed(linuxraw_input_t *linuxraw, const struct snes_keybind *binds, unsigned id) +{ + if (id < RARCH_BIND_LIST_END) + { + const struct snes_keybind *bind = &binds[id]; + return bind->valid && linuxraw_key_pressed(linuxraw, binds[id].key); + } + else + return false; +} + +static bool linuxraw_bind_button_pressed(void *data, int key) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + return linuxraw_is_pressed(linuxraw, g_settings.input.binds[0], key) || + input_sdl.key_pressed(linuxraw->sdl, key); +} + +static int16_t linuxraw_input_state(void *data, const struct snes_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + + switch (device) + { + case RETRO_DEVICE_JOYPAD: + return linuxraw_is_pressed(linuxraw, binds[port], id) || + input_sdl.input_state(linuxraw->sdl, binds, port, device, index, id); + + default: + return 0; + } +} + +static void linuxraw_input_free(void *data) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + input_sdl.free(linuxraw->sdl); + linuxraw_resetKbmd(); + free(data); +} + +static void linuxraw_input_poll(void *data) +{ + linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; + uint8_t c; + uint16_t t; + + while (read(0, &c, 1) > 0) + { + bool pressed = !(c & 0x80); + c &= ~0x80; + + // ignore extended scancodes + if (!c) + read(0, &t, 2); + else + linuxraw->state[c] = pressed; + } + + if (linuxraw->state[KEY_C] && (linuxraw->state[KEY_LEFTCTRL] || linuxraw->state[KEY_RIGHTCTRL])) + kill(getpid(), SIGINT); + + input_sdl.poll(linuxraw->sdl); +} + +const input_driver_t input_linuxraw = { + linuxraw_input_init, + linuxraw_input_poll, + linuxraw_input_state, + linuxraw_bind_button_pressed, + linuxraw_input_free, + "linuxraw" +};