diff --git a/config.def.h b/config.def.h index aba9548a2b..e671f4058a 100644 --- a/config.def.h +++ b/config.def.h @@ -108,6 +108,9 @@ static const bool fullscreen = false; // To start in Fullscreen or not static const unsigned fullscreen_x = 0; // Fullscreen resolution. A value of 0 uses the desktop resolution. static const unsigned fullscreen_y = 0; +// Force 16-bit colors. +static const bool force_16bit = false; + // Video VSYNC (recommended) static const bool vsync = true; diff --git a/general.h b/general.h index 4d1d1b2a58..f1d7e3033e 100644 --- a/general.h +++ b/general.h @@ -86,6 +86,7 @@ struct settings float msg_pos_x; float msg_pos_y; + bool force_16bit; } video; struct diff --git a/gfx/gl.c b/gfx/gl.c index dd50d4e63a..9603fece18 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -907,7 +907,7 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, video->vsync ? 1 : 0); - if (!SDL_SetVideoMode(video->width, video->height, 0, SDL_OPENGL | SDL_RESIZABLE | (video->fullscreen ? SDL_FULLSCREEN : 0))) + if (!SDL_SetVideoMode(video->width, video->height, g_settings.video.force_16bit ? 16 : 0, SDL_OPENGL | SDL_RESIZABLE | (video->fullscreen ? SDL_FULLSCREEN : 0))) return NULL; // Remove that ugly mouse :D diff --git a/gfx/sdl.c b/gfx/sdl.c index 3a152179dc..f070f98a0d 100644 --- a/gfx/sdl.c +++ b/gfx/sdl.c @@ -29,6 +29,7 @@ struct sdl_video { SDL_Surface *screen, *buffer; bool quitting; + bool rgb32; }; static void sdl_gfx_free(void *data) @@ -59,7 +60,7 @@ static void* sdl_gfx_init(const video_info_t *video, const input_driver_t **inpu 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 | SDL_DOUBLEBUF | (video->fullscreen ? SDL_FULLSCREEN : 0)); + vid->screen = SDL_SetVideoMode(video->width, video->height, (g_settings.video.force_16bit || !video->rgb32) ? 15 : 32, SDL_HWSURFACE | SDL_DOUBLEBUF | (video->fullscreen ? SDL_FULLSCREEN : 0)); if (!vid->screen) { SSNES_ERR("Failed to init SDL surface.\n"); @@ -67,8 +68,14 @@ static void* sdl_gfx_init(const video_info_t *video, const input_driver_t **inpu } SDL_ShowCursor(SDL_DISABLE); - vid->buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 256 * video->input_scale, 256 * video->input_scale, 15, - 0x7c00, 0x03e0, 0x001f, 0); + + if (g_settings.video.force_16bit || !video->rgb32) + vid->buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 256 * video->input_scale, 256 * video->input_scale, 15, + 0x7c00, 0x03e0, 0x001f, 0); + else + vid->buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 256 * video->input_scale, 256 * video->input_scale, 32, + 0, 0, 0, 0); + if (!vid->buffer) { SSNES_ERR("SDL_CreateRGBSurface failed: %s\n", SDL_GetError()); @@ -85,6 +92,8 @@ static void* sdl_gfx_init(const video_info_t *video, const input_driver_t **inpu else *input = NULL; + vid->rgb32 = video->rgb32; + return vid; error: @@ -92,6 +101,27 @@ error: return NULL; } +static inline uint16_t conv_pixel(uint32_t pix) +{ + uint16_t r = (pix & 0xf8000000) >> 17; + uint16_t g = (pix & 0x00f80000) >> 14; + uint16_t b = (pix & 0x0000f800) >> 11; + return r | g | b; +} + +static void convert_32bit_15bit(uint16_t *out, unsigned outpitch, const uint32_t *input, unsigned width, unsigned height, unsigned pitch) +{ + for (unsigned y = 0; y < height; y++) + { + for (unsigned x = 0; x < width; x++) + { + out[x] = conv_pixel(input[x]); + } + out += outpitch >> 1; + input += pitch >> 2; + } +} + static bool sdl_gfx_frame(void *data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char *msg) { (void)msg; @@ -101,11 +131,30 @@ static bool sdl_gfx_frame(void *data, const void* frame, unsigned width, unsigne SDL_LockSurface(vid->buffer); // :( - for (unsigned y = 0; y < height; y++) + // 15-bit -> 15-bit + if (!vid->rgb32) { - 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)); + 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)); + } + } + // 32-bit -> 15-bit + else if (vid->rgb32 && g_settings.video.force_16bit) + { + convert_32bit_15bit(vid->buffer->pixels, vid->buffer->pitch, frame, width, height, pitch); + } + // 32-bit -> 32-bit + else + { + for (unsigned y = 0; y < height; y++) + { + uint32_t *dest = (uint32_t*)vid->buffer->pixels + ((y * vid->buffer->pitch) >> 2); + const uint32_t *src = (const uint32_t*)frame + ((y * pitch) >> 2); + memcpy(dest, src, width * sizeof(uint32_t)); + } } if (SDL_MUSTLOCK(vid->buffer)) @@ -126,7 +175,6 @@ static bool sdl_gfx_frame(void *data, const void* frame, unsigned width, unsigne }; SDL_SoftStretch(vid->buffer, &src, vid->screen, &dest); - SDL_UpdateRect(vid->screen, dest.x, dest.y, dest.w, dest.h); char buf[128]; if (gfx_window_title(buf, sizeof(buf))) diff --git a/settings.c b/settings.c index 58b963e29a..5b1cd160c5 100644 --- a/settings.c +++ b/settings.c @@ -108,6 +108,7 @@ static void set_defaults(void) g_settings.video.fullscreen = fullscreen; g_settings.video.fullscreen_x = fullscreen_x; g_settings.video.fullscreen_y = fullscreen_y; + g_settings.video.force_16bit = force_16bit; g_settings.video.vsync = vsync; g_settings.video.smooth = video_smooth; g_settings.video.force_aspect = force_aspect; @@ -285,6 +286,7 @@ static void parse_config_file(void) CONFIG_GET_INT(video.fullscreen_x, "video_fullscreen_x"); CONFIG_GET_INT(video.fullscreen_y, "video_fullscreen_y"); CONFIG_GET_BOOL(video.fullscreen, "video_fullscreen"); + CONFIG_GET_BOOL(video.force_16bit, "video_force_16bit"); CONFIG_GET_BOOL(video.vsync, "video_vsync"); CONFIG_GET_BOOL(video.smooth, "video_smooth"); CONFIG_GET_BOOL(video.force_aspect, "video_force_aspect"); diff --git a/ssnes.cfg b/ssnes.cfg index 140eda3ccc..7563c70732 100644 --- a/ssnes.cfg +++ b/ssnes.cfg @@ -16,6 +16,9 @@ # Start in fullscreen. Can be changed at runtime. # video_fullscreen = false +# Force 16-bit colors. Apparently some video cards in use today have troubles with 32-bit ... +# video_force_16bit = false + # Video vsync. # video_vsync = true