From d317a9773f8721365f1b397e0e39301f0dcfe357 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 21 Apr 2011 03:23:44 +0200 Subject: [PATCH] Start on SDL video driver. --- Makefile | 2 +- Makefile.win32 | 2 +- config.def.h | 1 + driver.c | 1 + driver.h | 3 +- gfx/gl.c | 2 +- gfx/sdl.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++ gfx/xvideo.c | 2 +- settings.c | 3 + 9 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 gfx/sdl.c diff --git a/Makefile b/Makefile index e4b04e2d9e..95f6cae0b5 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,7 @@ ifeq ($(HAVE_PULSE), 1) endif ifeq ($(HAVE_SDL), 1) - OBJ += gfx/gl.o input/sdl.o audio/sdl.o audio/buffer.o + OBJ += gfx/sdl.o gfx/gl.o input/sdl.o audio/sdl.o audio/buffer.o DEFINES += $(SDL_CFLAGS) LIBS += $(SDL_LIBS) ifeq ($(OSX),1) diff --git a/Makefile.win32 b/Makefile.win32 index 1bb41fde16..ad8daf0546 100644 --- a/Makefile.win32 +++ b/Makefile.win32 @@ -33,7 +33,7 @@ else endif ifeq ($(HAVE_SDL), 1) - OBJ += gfx/gl.o input/sdl.o audio/sdl.o audio/buffer.o + OBJ += gfx/sdl.o gfx/gl.o input/sdl.o audio/sdl.o audio/buffer.o LIBS += $(SDL_LIBS) -lopengl32 DEFINES += $(SDL_CFLAGS) -DHAVE_SDL endif diff --git a/config.def.h b/config.def.h index bec4ecd141..aba9548a2b 100644 --- a/config.def.h +++ b/config.def.h @@ -44,6 +44,7 @@ ///////////////// Drivers #define VIDEO_GL 0 #define VIDEO_XVIDEO 11 +#define VIDEO_SDL 13 //////////////////////// #define AUDIO_RSOUND 1 #define AUDIO_OSS 2 diff --git a/driver.c b/driver.c index ebb460a580..70e8807d15 100644 --- a/driver.c +++ b/driver.c @@ -61,6 +61,7 @@ static const audio_driver_t *audio_drivers[] = { static const video_driver_t *video_drivers[] = { #ifdef HAVE_SDL &video_gl, + &video_sdl, #endif #ifdef HAVE_XVIDEO &video_xvideo, diff --git a/driver.h b/driver.h index 02c3b6ed32..c9f2fb3612 100644 --- a/driver.h +++ b/driver.h @@ -111,7 +111,7 @@ typedef struct input_driver typedef struct video_driver { - void* (*init)(video_info_t *video, const input_driver_t **input, void **input_data); + void* (*init)(const video_info_t *video, const input_driver_t **input, void **input_data); // Should the video driver act as an input driver as well? :) The video init might preinitialize an input driver to override the settings in case the video driver relies on input driver for event handling, e.g. bool (*frame)(void* data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char *msg); // msg is for showing a message on the screen along with the video frame. void (*set_nonblock_state)(void* data, bool toggle); // Should we care about syncing to vblank? Fast forwarding. @@ -156,6 +156,7 @@ extern const audio_driver_t audio_xa; extern const audio_driver_t audio_pulse; extern const video_driver_t video_gl; extern const video_driver_t video_xvideo; +extern const video_driver_t video_sdl; extern const input_driver_t input_sdl; extern const input_driver_t input_x; //////////////////////////////////////////////// diff --git a/gfx/gl.c b/gfx/gl.c index 25b67e0578..dd50d4e63a 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -893,7 +893,7 @@ static void gl_set_nonblock_state(void *data, bool state) } } -static void* gl_init(video_info_t *video, const input_driver_t **input, void **input_data) +static void* gl_init(const video_info_t *video, const input_driver_t **input, void **input_data) { if (SDL_Init(SDL_INIT_VIDEO) < 0) return NULL; diff --git a/gfx/sdl.c b/gfx/sdl.c new file mode 100644 index 0000000000..a7763c11d4 --- /dev/null +++ b/gfx/sdl.c @@ -0,0 +1,160 @@ +/* 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 . + */ + +#include "SDL.h" +#include "driver.h" +#include +#include +#include +#include "general.h" +#include "input/ssnes_sdl_input.h" + +typedef struct sdl_video sdl_video_t; +struct sdl_video +{ + SDL_Surface *screen, *buffer; + bool quitting; +}; + +static void sdl_gfx_free(void *data) +{ + sdl_video_t *vid = data; + if (!vid) + return; + + if (vid->buffer) + SDL_FreeSurface(vid->screen); + + SDL_QuitSubSystem(SDL_INIT_VIDEO); + + free(vid); +} + +static void* sdl_gfx_init(const video_info_t *video, const input_driver_t **input, void **input_data) +{ + SDL_InitSubSystem(SDL_INIT_VIDEO); + + sdl_video_t *vid = calloc(1, sizeof(*vid)); + if (!vid) + return NULL; + + const SDL_VideoInfo *video_info = SDL_GetVideoInfo(); + assert(video_info); + unsigned full_x = video_info->current_w; + unsigned full_y = video_info->current_h; + SSNES_LOG("Detecting desktop resolution %ux%u.\n", full_x, full_y); + + vid->screen = SDL_SetVideoMode(video->width, video->height, 15, SDL_HWSURFACE | (video->fullscreen ? SDL_FULLSCREEN : 0)); + if (!vid->screen) + { + SSNES_ERR("Failed to init SDL surface.\n"); + goto error; + } + + SDL_ShowCursor(SDL_DISABLE); + vid->buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 256 * video->input_scale, 256 * video->input_scale, 15, + 0x7c00, 0x03e0, 0x001f, 0); + if (!vid->buffer) + { + SSNES_ERR("SDL_CreateRGBSurface failed: %s\n", SDL_GetError()); + goto error; + } + + sdl_input_t *sdl_input = input_sdl.init(); + if (sdl_input) + { + sdl_input->quitting = &vid->quitting; + *input = &input_sdl; + *input_data = sdl_input; + } + else + *input = NULL; + + return vid; + +error: + sdl_gfx_free(vid); + return NULL; +} + +static bool sdl_gfx_frame(void *data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char *msg) +{ + (void)msg; + sdl_video_t *vid = data; + + if (SDL_MUSTLOCK(vid->buffer)) + SDL_LockSurface(vid->buffer); + + for (unsigned y = 0; y < height; y++) + { + uint16_t *dest = (uint16_t*)vid->buffer->pixels + ((y * vid->buffer->pitch) >> 1); + const uint16_t *src = (const uint16_t*)frame + ((y * pitch) >> 1); + memcpy(dest, src, width * sizeof(uint16_t)); + } + + if (SDL_MUSTLOCK(vid->buffer)) + SDL_UnlockSurface(vid->buffer); + + SDL_Rect src = { + .x = 0, + .y = 0, + .w = width, + .h = height + }; + + SDL_Rect dest = { + .x = 0, + .y = 0, + .w = vid->screen->w, + .h = vid->screen->h + }; + + SDL_SoftStretch(vid->buffer, &src, vid->screen, &dest); + SDL_UpdateRect(vid->screen, dest.x, dest.y, dest.w, dest.h); + + return true; +} + +static void sdl_gfx_set_nonblock_state(void *data, bool state) +{ + (void)data; // Can SDL even do this? + (void)state; +} + +static bool sdl_gfx_alive(void *data) +{ + sdl_video_t *vid = data; + return !vid->quitting; +} + +static bool sdl_gfx_focus(void *data) +{ + (void)data; + return (SDL_GetAppState() & (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) == (SDL_APPINPUTFOCUS | SDL_APPACTIVE); +} + + +const video_driver_t video_sdl = { + .init = sdl_gfx_init, + .frame = sdl_gfx_frame, + .alive = sdl_gfx_alive, + .set_nonblock_state = sdl_gfx_set_nonblock_state, + .focus = sdl_gfx_focus, + .free = sdl_gfx_free, + .ident = "sdl" +}; + diff --git a/gfx/xvideo.c b/gfx/xvideo.c index d287e836cd..e0fe94c160 100644 --- a/gfx/xvideo.c +++ b/gfx/xvideo.c @@ -298,7 +298,7 @@ static void render32_uyvy(xv_t *xv, const void *input_, unsigned width, unsigned } -static void* xv_init(video_info_t *video, const input_driver_t **input, void **input_data) +static void* xv_init(const video_info_t *video, const input_driver_t **input, void **input_data) { xv_t *xv = calloc(1, sizeof(*xv)); if (!xv) diff --git a/settings.c b/settings.c index 4d63bca723..58b963e29a 100644 --- a/settings.c +++ b/settings.c @@ -47,6 +47,9 @@ static void set_defaults(void) case VIDEO_XVIDEO: def_video = "xvideo"; break; + case VIDEO_SDL: + def_video = "sdl"; + break; default: break; }