Start working towards SDL 1.2/1.3 compat.

This commit is contained in:
Themaister 2011-09-13 14:06:49 +02:00
parent 4c40e56060
commit 924848fdad
14 changed files with 306 additions and 146 deletions

View File

@ -89,7 +89,7 @@ ifeq ($(HAVE_COREAUDIO), 1)
endif
ifeq ($(HAVE_SDL), 1)
OBJ += gfx/sdl.o gfx/gl.o input/sdl.o audio/sdl.o fifo_buffer.o
OBJ += gfx/sdl.o gfx/gl.o gfx/sdlwrap.o input/sdl.o audio/sdl.o fifo_buffer.o
DEFINES += $(SDL_CFLAGS) $(BSD_LOCAL_INC)
LIBS += $(SDL_LIBS)
ifeq ($(OSX),1)

View File

@ -32,7 +32,7 @@ LDFLAGS = -L. -static-libgcc -s
LDCXXFLAGS = -static-libstdc++
ifeq ($(HAVE_SDL), 1)
OBJ += gfx/sdl.o gfx/gl.o input/sdl.o audio/sdl.o fifo_buffer.o
OBJ += gfx/sdl.o gfx/gl.o gfx/sdlwrap.o input/sdl.o audio/sdl.o fifo_buffer.o
LIBS += -lSDL -lopengl32
DEFINES += -ISDL -DHAVE_SDL
endif

View File

@ -56,7 +56,7 @@ enum
struct snes_keybind
{
int id;
uint16_t key;
uint32_t key;
uint16_t joykey;
uint32_t joyaxis;
};

View File

@ -24,6 +24,7 @@
#include <stdint.h>
#include "dynamic.h"
#include "general.h"
#include "sdlwrap.h"
static bool g_input_dead = true;
static bool g_video_dead = true;
@ -272,6 +273,11 @@ static bool setup_video(ext_t *ext, const video_info_t *video, const input_drive
static void* video_ext_init(const video_info_t *video, const input_driver_t **input, void **input_data)
{
#if SDL_MODERN
SSNES_ERR("External driver API not compatible with SDL 1.3 input API!\n");
return NULL;
#endif
ext_t *ext = calloc(1, sizeof(*ext));
if (!ext)
return NULL;

View File

@ -112,23 +112,3 @@ void gfx_set_dwm(void)
}
#endif
#include "SDL_syswm.h"
#include "SDL.h"
#if !defined(__APPLE__) && !defined(_WIN32)
void gfx_get_window_size(unsigned *width, unsigned *height)
{
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
SDL_GetWMInfo(&info);
XWindowAttributes target;
info.info.x11.lock_func();
XGetWindowAttributes(info.info.x11.display, info.info.x11.window,
&target);
info.info.x11.unlock_func();
*width = target.width;
*height = target.height;
}
#endif

View File

@ -28,8 +28,4 @@ void gfx_window_title_reset(void);
void gfx_set_dwm(void);
#endif
#if !defined(__APPLE__) && !defined(_WIN32)
void gfx_get_window_size(unsigned *width, unsigned *height);
#endif
#endif

114
gfx/gl.c
View File

@ -33,6 +33,7 @@
#include "gl_common.h"
#include "gfx_common.h"
#include "sdlwrap.h"
#define NO_SDL_GLEXT
#include "SDL.h"
@ -689,43 +690,20 @@ static inline void set_texture_coords(GLfloat *coords, GLfloat xamt, GLfloat yam
static void check_window(gl_t *gl)
{
SDL_Event event;
bool quit, resize;
// Search for events we care about ...
while (SDL_PollEvent(&event))
sdlwrap_check_window(&quit,
&resize, &gl->win_width, &gl->win_height,
gl->frame_count);
if (quit)
{
switch (event.type)
{
case SDL_QUIT:
gl->quitting = true;
break;
case SDL_VIDEORESIZE:
gl->should_resize = true;
gl->win_width = event.resize.w;
gl->win_height = event.resize.h;
break;
default:
break;
}
gl->quitting = true;
}
#if !defined(__APPLE__) && !defined(_WIN32)
// Hack to workaround limitations in tiling WMs ...
if (!gl->should_resize && !gl->fullscreen)
else if (resize)
{
unsigned new_width, new_height;
gfx_get_window_size(&new_width, &new_height);
if ((new_width != gl->win_width || new_height != gl->win_height) || (gl->frame_count == 10)) // Ugly hack :D
{
gl->should_resize = true;
gl->win_width = new_width;
gl->win_height = new_height;
SSNES_LOG("GL: Verified window size: %u x %u\n", gl->win_width, gl->win_height);
}
gl->should_resize = true;
}
#endif
}
static bool gl_frame(void *data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
@ -806,13 +784,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
{
gl->should_resize = false;
// Resizing is broken on OSX, yay. :)
#ifndef __APPLE__
const int resizable_ = SDL_RESIZABLE;
#else
const int resizable_ = 0;
#endif
SDL_SetVideoMode(gl->win_width, gl->win_height, 0, SDL_OPENGL | (g_settings.video.fullscreen ? SDL_FULLSCREEN : resizable_));
sdlwrap_set_video_mode(gl->win_width, gl->win_height, 0, g_settings.video.fullscreen);
#ifdef HAVE_FBO
if (!gl->render_to_tex)
@ -884,7 +856,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
#endif
#ifdef HAVE_FBO
// Need to preserve the "flipped" state when in FBO too to have
// Need to preserve the "flipped" state when in FBO as well to have
// consistent texture coordinates.
if (gl->render_to_tex)
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes);
@ -996,8 +968,9 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
char buf[128];
if (gfx_window_title(buf, sizeof(buf)))
SDL_WM_SetCaption(buf, NULL);
SDL_GL_SwapBuffers();
sdlwrap_wm_set_caption(buf);
sdlwrap_swap_buffers();
return true;
}
@ -1027,41 +1000,13 @@ static void gl_free(void *data)
free(gl);
}
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#endif
static void gl_set_nonblock_state(void *data, bool state)
{
gl_t *gl = data;
if (gl->vsync)
{
SSNES_LOG("GL VSync => %s\n", state ? "off" : "on");
#if defined(_WIN32)
static BOOL (APIENTRY *wgl_swap_interval)(int) = NULL;
if (!wgl_swap_interval)
{
SDL_SYM_WRAP(wgl_swap_interval, "wglSwapIntervalEXT");
}
if (wgl_swap_interval) wgl_swap_interval(state ? 0 : 1);
#elif defined(__APPLE__)
GLint val = state ? 0 : 1;
CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &val);
#else
static int (*glx_swap_interval)(int) = NULL;
if (!glx_swap_interval)
{
SDL_SYM_WRAP(glx_swap_interval, "glXSwapIntervalSGI");
}
if (!glx_swap_interval)
{
SDL_SYM_WRAP(glx_swap_interval, "glXSwapIntervalMESA");
}
if (glx_swap_interval)
glx_swap_interval(state ? 0 : 1);
else
SSNES_WARN("Could not find GLX VSync call. :(\n");
#endif
sdlwrap_set_swap_interval(state ? 0 : 1, true);
}
}
@ -1080,22 +1025,16 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
unsigned full_y = video_info->current_h;
SSNES_LOG("Detecting desktop resolution %ux%u.\n", full_x, full_y);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, video->vsync ? 1 : 0);
sdlwrap_set_swap_interval(video->vsync ? 1 : 0, false);
// Resizing is broken on OSX, yay. :)
#ifndef __APPLE__
const int resizable_ = SDL_RESIZABLE;
#else
const int resizable_ = 0;
#endif
if (!SDL_SetVideoMode(video->width, video->height, g_settings.video.force_16bit ? 16 : 0, SDL_OPENGL | (video->fullscreen ? SDL_FULLSCREEN : resizable_)))
if (!sdlwrap_set_video_mode(video->width, video->height,
g_settings.video.force_16bit ? 16 : 0, video->fullscreen))
return NULL;
gfx_window_title_reset();
char buf[128];
if (gfx_window_title(buf, sizeof(buf)))
SDL_WM_SetCaption(buf, NULL);
sdlwrap_wm_set_caption(buf);
// Remove that ugly mouse :D
SDL_ShowCursor(SDL_DISABLE);
@ -1120,18 +1059,7 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
gl->vsync = video->vsync;
gl->fullscreen = video->fullscreen;
int attr = 0;
SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &attr);
if (attr <= 0 && video->vsync)
{
SSNES_WARN("SDL failed to setup VSync, attempting to recover using native calls!\n");
gl_set_nonblock_state(gl, false);
}
attr = 0;
SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &attr);
if (attr <= 0)
SSNES_WARN("GL double buffer has not been enabled!\n");
gl->full_x = full_x;
gl->full_y = full_y;

View File

@ -106,13 +106,6 @@ struct gl_tex_info
GLfloat coord[8];
};
// Not legal to cast void* to fn-pointer. Need dirty hack to be compilant.
// sizeof(void*) == sizeof(void (*)(void)) is asserted earlier.
#define SDL_SYM_WRAP(sym, symbol) { \
void *sym__ = SDL_GL_GetProcAddress(symbol); \
memcpy(&(sym), &sym__, sizeof(void*)); \
}
// Windows ... <_<
#if (defined(HAVE_XML) || defined(HAVE_CG)) && defined(_WIN32)
extern PFNGLCLIENTACTIVETEXTUREPROC pglClientActiveTexture;

203
gfx/sdlwrap.c Normal file
View File

@ -0,0 +1,203 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES 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.
*
* SSNES 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 SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "sdlwrap.h"
#include "SDL_syswm.h"
#include "general.h"
#include <assert.h>
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#endif
// SDL 1.2 is portable, sure, but you still need some platform specific workarounds ;)
// Hopefully SDL 1.3 will solve this more cleanly :D
static bool g_fullscreen;
static unsigned g_interval;
void sdlwrap_set_swap_interval(unsigned interval, bool inited)
{
g_interval = interval;
if (inited)
{
#if defined(_WIN32)
static BOOL (APIENTRY *wgl_swap_interval)(int) = NULL;
if (!wgl_swap_interval)
{
SDL_SYM_WRAP(wgl_swap_interval, "wglSwapIntervalEXT");
}
if (wgl_swap_interval) wgl_swap_interval(g_interval);
#elif defined(__APPLE__)
GLint val = g_interval;
CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &val);
#else
static int (*glx_swap_interval)(int) = NULL;
if (!glx_swap_interval)
{
SDL_SYM_WRAP(glx_swap_interval, "glXSwapIntervalSGI");
}
if (!glx_swap_interval)
{
SDL_SYM_WRAP(glx_swap_interval, "glXSwapIntervalMESA");
}
if (glx_swap_interval)
glx_swap_interval(g_interval);
else
SSNES_WARN("Could not find GLX VSync call. :(\n");
#endif
}
}
bool sdlwrap_set_video_mode(
unsigned width, unsigned height,
unsigned bits, bool fullscreen)
{
// Resizing in windowed mode appears to be broken on OSX. Yay!
#ifndef __APPLE__
static const int resizable = SDL_RESIZABLE;
#else
static const int resizable = 0;
#endif
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
#if !SDL_MODERN
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, g_interval);
#endif
if (!SDL_SetVideoMode(width, height, bits,
SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : resizable)))
return false;
int attr = 0;
#if SDL_MODERN
SDL_GL_SetSwapInterval(g_interval);
#else
SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &attr);
if (attr <= 0 && g_interval)
{
SSNES_WARN("SDL failed to setup VSync, attempting to recover using native calls!\n");
sdlwrap_set_swap_interval(g_interval, true);
}
#endif
g_fullscreen = fullscreen;
attr = 0;
SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &attr);
if (attr <= 0)
SSNES_WARN("GL double buffer has not been enabled!\n");
return true;
}
void sdlwrap_wm_set_caption(const char *str)
{
SDL_WM_SetCaption(str, NULL);
}
void sdlwrap_swap_buffers(void)
{
SDL_GL_SwapBuffers();
}
bool sdlwrap_key_pressed(int key)
{
int num_keys;
#if SDL_MODERN
Uint8 *keymap = SDL_GetKeyboardState(&num_keys);
key = SDL_GetScancodeFromKey(key);
if (key >= num_keys)
return false;
return keymap[key];
#else
Uint8 *keymap = SDL_GetKeyState(&num_keys);
if (key >= num_keys)
return false;
return keymap[key];
#endif
}
#if !defined(__APPLE__) && !defined(_WIN32)
static void sdlwrap_get_window_size(unsigned *width, unsigned *height)
{
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
SDL_GetWMInfo(&info);
XWindowAttributes target;
#if SDL_MODERN
XGetWindowAttributes(info.info.x11.display, info.info.x11.window,
&target);
#else
info.info.x11.lock_func();
XGetWindowAttributes(info.info.x11.display, info.info.x11.window,
&target);
info.info.x11.unlock_func();
#endif
*width = target.width;
*height = target.height;
}
#endif
void sdlwrap_check_window(bool *quit,
bool *resize, unsigned *width, unsigned *height, unsigned frame_count)
{
*quit = false;
*resize = false;
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
*quit = true;
break;
case SDL_VIDEORESIZE:
*resize = true;
*width = event.resize.w;
*height = event.resize.h;
break;
}
}
#if !defined(__APPLE__) && !defined(_WIN32)
// Hack to workaround limitations in tiling WMs ...
if (!*resize && !g_fullscreen)
{
unsigned new_width, new_height;
sdlwrap_get_window_size(&new_width, &new_height);
if ((new_width != *width || new_height != *height) || (frame_count == 10)) // Ugly hack :D
{
*resize = true;
*width = new_width;
*height = new_height;
SSNES_LOG("GL: Verified window size: %u x %u\n", *width, *height);
}
}
#endif
}

62
gfx/sdlwrap.h Normal file
View File

@ -0,0 +1,62 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES 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.
*
* SSNES 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 SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
// Compatibility wrapper between SDL 1.2/1.3 for OpenGL.
// Wraps functions which differ in 1.2 and 1.3.
#ifndef __SDLWRAP_H
#define __SDLWRAP_H
#include <stdbool.h>
#include "SDL.h"
#include "SDL_version.h"
#if SDL_VERSION_ATLEAST(1, 3, 0)
#define SDL_MODERN 1
#else
#define SDL_MODERN 0
#endif
//#if SDL_MODERN
//#error "SDL 1.3 support not yet implemented!"
//#endif
// Not legal to cast void* to fn-pointer. Need workaround to be compliant.
#define SDL_SYM_WRAP(sym, symbol) { \
assert(sizeof(void*) == sizeof(void (*)(void))); \
void *sym__ = SDL_GL_GetProcAddress(symbol); \
memcpy(&(sym), &sym__, sizeof(void*)); \
}
void sdlwrap_set_swap_interval(unsigned interval, bool inited);
bool sdlwrap_set_video_mode(
unsigned width, unsigned height,
unsigned bits, bool fullscreen);
void sdlwrap_wm_set_caption(const char *str);
void sdlwrap_swap_buffers(void);
bool sdlwrap_key_pressed(int key);
void sdlwrap_check_window(bool *quit,
bool *resize, unsigned *width, unsigned *height, unsigned frame_count);
#endif

View File

@ -33,7 +33,7 @@
#define NO_SDL_GLEXT
#include "SDL.h"
#include "sdlwrap.h"
#include "SDL_opengl.h"
#include <stdlib.h>
#include <libxml/parser.h>

View File

@ -17,7 +17,7 @@
#include "driver.h"
#include "SDL.h"
#include "../gfx/sdlwrap.h"
#include <stdbool.h>
#include "general.h"
#include <stdint.h>
@ -76,16 +76,9 @@ static void* sdl_input_init(void)
return sdl;
}
static bool sdl_key_pressed(int key)
{
int num_keys;
Uint8 *keymap = SDL_GetKeyState(&num_keys);
if (key >= num_keys)
return false;
return keymap[key];
return sdlwrap_key_pressed(key);
}
#ifndef HAVE_DINPUT

View File

@ -41,7 +41,11 @@ struct key_bind
int sdl;
};
static int keysym_lut[SDLK_LAST];
#define LUT_SIZE 1024
#define LUT_MASK (LUT_SIZE - 1)
static int keysym_lut[LUT_SIZE];
static const struct key_bind lut_binds[] = {
{ XK_Left, SDLK_LEFT },
{ XK_Right, SDLK_RIGHT },
@ -130,7 +134,7 @@ 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].sdl] = lut_binds[i].x;
keysym_lut[lut_binds[i].sdl & LUT_MASK] = lut_binds[i].x;
}
static void* x_input_init(void)
@ -161,7 +165,7 @@ static void* x_input_init(void)
static bool x_key_pressed(x11_input_t *x11, int key)
{
key = keysym_lut[key];
key = keysym_lut[key & LUT_MASK];
int keycode = XKeysymToKeycode(x11->display, key);
bool ret = x11->state[keycode >> 3] & (1 << (keycode & 7));
return ret;

View File

@ -58,12 +58,7 @@ check_pkgconf PULSE libpulse
check_lib COREAUDIO "-framework AudioUnit" AudioUnitInitialize
check_pkgconf SDL sdl 1.2.10
check_critical SDL "Cannot find SDL 1.2 library."
check_pkgconf SDL_NEW sdl 1.3
if [ $HAVE_SDL_NEW = yes ]; then
echo "SSNES is not compatible with SDL 1.3 API, please use a recent 1.2 release."
exit 1
fi
check_critical SDL "Cannot find SDL library."
# On some distros, -lCg doesn't link against -lstdc++ it seems ...
check_lib_cxx CG -lCg cgCreateContext