diff --git a/Makefile.common b/Makefile.common index 34576dd4b0..5394c2c1a9 100644 --- a/Makefile.common +++ b/Makefile.common @@ -668,7 +668,7 @@ else ifeq ($(HAVE_BUILTINMBEDTLS), 1) DEFINES += -DMBEDTLS_SSL_DEBUG_ALL endif - # MinGW requires this for some reason, + # MinGW requires this for some reason, # even though the include paths are relative to the source INCLUDE_DIRS += -Ideps/mbedtls @@ -1576,8 +1576,14 @@ else ifeq ($(HAVE_SDL), 1) else ifeq ($(HAVE_SDL_DINGUX), 1) HAVE_SDL_COMMON = 1 DEF_FLAGS += -DHAVE_SDL -DHAVE_SDL_DINGUX - OBJ += gfx/drivers/sdl_dingux_gfx.o \ - input/drivers/sdl_dingux_input.o \ + + ifeq ($(RS90), 1) + OBJ += gfx/drivers/sdl_rs90_gfx.o + else + OBJ += gfx/drivers/sdl_dingux_gfx.o + endif + + OBJ += input/drivers/sdl_dingux_input.o \ input/drivers_joypad/sdl_dingux_joypad.o DEF_FLAGS += $(SDL_DINGUX_CFLAGS) LIBS += $(SDL_DINGUX_LIBS) @@ -2296,9 +2302,9 @@ ifeq ($(HAVE_CRTSWITCHRES), 1) $(DEPS_DIR)/switchres/resync_windows.o endif ifneq ($(findstring Linux,$(OS)),) - OBJ += $(DEPS_DIR)/switchres/display_linux.o + OBJ += $(DEPS_DIR)/switchres/display_linux.o ifeq ($(HAVE_X11)$(HAVE_XRANDR), 11) - OBJ += $(DEPS_DIR)/switchres/custom_video_xrandr.o + OBJ += $(DEPS_DIR)/switchres/custom_video_xrandr.o DEFINES += -DSR_WITH_XRANDR endif endif @@ -2325,9 +2331,9 @@ ifeq ($(HAVE_COCOA_COMMON),1) OBJ += input/drivers/cocoa_input.o \ ui/drivers/ui_cocoa.o \ ui/drivers/cocoa/cocoa_common.o - + ifeq ($(HAVE_OPENGL), 1) - DEFINES += -DGL_SILENCE_DEPRECATION + DEFINES += -DGL_SILENCE_DEPRECATION OBJ += gfx/drivers_context/cocoa_gl_ctx.o endif ifeq ($(HAVE_VULKAN), 1) @@ -2482,4 +2488,3 @@ ifeq ($(HAVE_ODROIDGO2), 1) endif ################################## - diff --git a/Makefile.rs90 b/Makefile.rs90 new file mode 100644 index 0000000000..cfb26c41d1 --- /dev/null +++ b/Makefile.rs90 @@ -0,0 +1,236 @@ +######################### +## Toolchain variables ## +######################### + +# Alpha toolchain +TOOLCHAIN_DIR=/opt/rs90-toolchain + +# All toolchain-related variables may be +# overridden via the command line +ifdef GCW0_CC +CC = $(GCW0_CC) +else +CC = $(TOOLCHAIN_DIR)/usr/bin/mipsel-rs90-linux-musl-gcc +endif + +ifdef GCW0_CXX +CXX = $(GCW0_CXX) +else +CXX = $(TOOLCHAIN_DIR)/usr/bin/mipsel-rs90-linux-musl-g++ +endif + +ifdef GCW0_STRIP +STRIP = $(GCW0_STRIP) +else +STRIP = $(TOOLCHAIN_DIR)/usr/bin/mipsel-rs90-linux-musl-strip +endif + +GCW0_SDL_CONFIG ?= $(TOOLCHAIN_DIR)/usr/mipsel-rs90-linux-musl/sysroot/usr/bin/sdl-config +GCW0_FREETYPE_CONFIG ?= $(TOOLCHAIN_DIR)/usr/mipsel-rs90-linux-musl/sysroot/usr/bin/freetype-config +GCW0_MK_SQUASH_FS ?= $(TOOLCHAIN_DIR)/usr/bin/mksquashfs + +GCW0_INC_DIR ?= $(TOOLCHAIN_DIR)/usr/mipsel-rs90-linux-musl/sysroot/usr/include +GCW0_LIB_DIR ?= $(TOOLCHAIN_DIR)/usr/mipsel-rs90-linux-musl/sysroot/usr/lib + +######################### +######################### + +PACKAGE_NAME = retroarch + +DEBUG ?= 0 + +RS90 = 1 +DINGUX = 1 +DINGUX_BETA = 1 +HAVE_SCREENSHOTS = 0 +HAVE_REWIND = 1 +HAVE_7ZIP = 1 +HAVE_AL = 0 +# ALSA freezes when switching back from menu +HAVE_ALSA = 1 +HAVE_DSP_FILTER = 1 +HAVE_VIDEO_FILTER = 1 +HAVE_STATIC_VIDEO_FILTERS = 1 +HAVE_STATIC_AUDIO_FILTERS = 1 +HAVE_FILTERS_BUILTIN = 1 +HAVE_BUILTINMBEDTLS = 0 +HAVE_BUILTINZLIB = 1 +HAVE_C99 = 1 +HAVE_CC = 1 +HAVE_CC_RESAMPLER = 1 + +HAVE_CHD = 1 +HAVE_COMMAND = 0 +HAVE_CXX = 1 +HAVE_DR_MP3 = 1 +HAVE_DYNAMIC = 1 +HAVE_EGL = 0 +HAVE_FREETYPE = 0 +HAVE_GDI = 1 +HAVE_GETADDRINFO = 0 +HAVE_GETOPT_LONG = 1 +HAVE_GLSL = 0 +HAVE_HID = 1 +HAVE_IBXM = 1 +HAVE_IMAGEVIEWER = 1 +HAVE_LANGEXTRA = 0 +HAVE_LIBRETRODB = 1 +HAVE_MENU = 1 +HAVE_MENU_COMMON = 1 +HAVE_GFX_WIDGETS = 0 +HAVE_MMAP = 1 +HAVE_OPENDINGUX_FBDEV = 0 +HAVE_OPENGL = 0 +HAVE_OPENGL1 = 0 +HAVE_OPENGLES = 0 +HAVE_OPENGLES3 = 0 +HAVE_OPENGL_CORE = 0 +HAVE_OPENSSL = 1 +HAVE_OVERLAY = 0 +HAVE_RBMP = 1 +HAVE_RJPEG = 1 +HAVE_RPILED = 0 +HAVE_RPNG = 1 +HAVE_RUNAHEAD = 1 +HAVE_SDL_DINGUX = 1 +HAVE_SHADERPIPELINE = 0 +HAVE_STB_FONT = 0 +HAVE_STB_IMAGE = 1 +HAVE_STB_VORBIS = 1 +HAVE_STDIN_CMD = 0 +HAVE_STRCASESTR = 1 +HAVE_THREADS = 1 +HAVE_UDEV = 1 +HAVE_RGUI = 1 +HAVE_MATERIALUI = 0 +HAVE_XMB = 0 +HAVE_OZONE = 0 +HAVE_ZLIB = 1 +HAVE_CONFIGFILE = 1 +HAVE_PATCH = 1 +HAVE_CHEATS = 1 +HAVE_CHEEVOS = 0 +HAVE_LIBSHAKE = 0 +HAVE_TINYALSA = 1 +HAVE_NEAREST_RESAMPLER = 1 + +OS = Linux +TARGET = retroarch +OPK_NAME = retroarch_rs90_odbeta.opk + +OBJ := +LINK := $(CXX) +DEF_FLAGS := -mplt -mno-shared +DEF_FLAGS += -ffunction-sections -fdata-sections +DEF_FLAGS += -I. -Ideps -Ideps/stb -DRS90=1 -DDINGUX=1 -DDINGUX_BETA=1 -MMD +DEF_FLAGS += -Wall -Wno-unused-variable +DEF_FLAGS += -std=gnu99 -D_GNU_SOURopendinguxCE -flto -lasound +LIBS := -ldl -lz -lrt -ludev -pthread +CFLAGS := +CXXFLAGS := -fno-exceptions -fno-rtti -std=c++11 -D__STDC_CONSTANT_MACROS +ASFLAGS := +LDFLAGS := -Wl,--gc-sections +INCLUDE_DIRS = -I$(GCW0_INC_DIR) +LIBRARY_DIRS = -L$(GCW0_LIB_DIR) +DEFINES := -DRARCH_INTERNAL -D_FILE_OFFSET_BITS=64 -UHAVE_STATIC_DUMMY +DEFINES += -DHAVE_C99=1 -DHAVE_CXX=1 +DEFINES += -DHAVE_GETOPT_LONG=1 -DHAVE_STRCASESTR=1 -DHAVE_DYNAMIC=1 +DEFINES += -DHAVE_FILTERS_BUILTIN +DEFINES += -DHAVE_UDEV=1 +DEFINES += -DHAVE_ALSA +DEFINES += -DCC_RESAMPLER_PRECISION=0 + +SDL_DINGUX_CFLAGS := $(shell $(GCW0_SDL_CONFIG) --cflags) +SDL_DINGUX_LIBS := $(shell $(GCW0_SDL_CONFIG) --libs) +FREETYPE_CFLAGS := $(shell $(GCW0_FREETYPE_CONFIG) --cflags) +FREETYPE_LIBS := $(shell $(GCW0_FREETYPE_CONFIG) --libs) +# AL_LIBS := -lopenal +MMAP_LIBS = -lc + +OBJDIR_BASE := obj-unix + +ifeq ($(DEBUG), 1) + OBJDIR := $(OBJDIR_BASE)/debug + DEF_FLAGS += -O0 -g -DDEBUG -D_DEBUG +else + OBJDIR := $(OBJDIR_BASE)/release + DEF_FLAGS += -Ofast -DNDEBUG +endif + +include Makefile.common + +DEF_FLAGS += $(INCLUDE_DIRS) +LDFLAGS += $(CFLAGS) $(CXXFLAGS) $(DEF_FLAGS) +CFLAGS += $(DEF_FLAGS) +CXXFLAGS += $(DEF_FLAGS) + +HEADERS = $(wildcard */*/*.h) $(wildcard */*.h) $(wildcard *.h) + +Q := @ + +RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ)) + +define DESKTOP_ENTRY +[Desktop Entry] +Name=RetroArch +Comment=Frontend for emulators, game engines +Exec=retroarch +Terminal=false +Type=Application +StartupNotify=true +Icon=retroarch +Categories=emulators; +X-OD-NeedsDownscaling=true +endef +export DESKTOP_ENTRY + +all: $(TARGET) opk + +-include $(RARCH_OBJ:.o=.d) + +SYMBOL_MAP := -Wl,-Map=output.map + +$(TARGET): $(RARCH_OBJ) + @$(if $(Q), $(shell echo echo LD $@),) + $(Q)$(LINK) -o $@ $(RARCH_OBJ) $(LIBS) $(LDFLAGS) $(LIBRARY_DIRS) + +$(OBJDIR)/%.o: %.c + @mkdir -p $(dir $@) + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) $(CPPFLAGS) $(CFLAGS) $(DEFINES) -c -o $@ $< + +$(OBJDIR)/%.o: %.cpp + @mkdir -p $(dir $@) + @$(if $(Q), $(shell echo echo CXX $<),) + $(Q)$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEFINES) -MMD -c -o $@ $< + +$(OBJDIR)/%.o: %.m + @mkdir -p $(dir $@) + @$(if $(Q), $(shell echo echo OBJC $<),) + $(Q)$(CXX) $(OBJCFLAGS) $(DEFINES) -MMD -c -o $@ $< + +$(OBJDIR)/%.o: %.S $(HEADERS) + @mkdir -p $(dir $@) + @$(if $(Q), $(shell echo echo AS $<),) + $(Q)$(CC) $(CFLAGS) $(ASFLAGS) $(DEFINES) -c -o $@ $< + +clean: + rm -rf $(OBJDIR_BASE) + rm -f $(TARGET) + rm -f *.d + rm -rf $(OPK_NAME) + +opk: $(TARGET) + echo "$$DESKTOP_ENTRY" > default.rs90.desktop + rm -f $(OPK_NAME) + cp media/ico_src/icon32.png retroarch.png +ifeq ($STRIP_BIN, 1) + $(STRIP) --strip-unneeded retroarch +endif + $(GCW0_MK_SQUASH_FS) retroarch default.rs90.desktop retroarch.png $(OPK_NAME) -all-root -no-xattrs -noappend -no-exports + rm -f default.rs90.desktop retroarch.png + +.PHONY: all clean opk + +print-%: + @echo '$*=$($*)' diff --git a/config.def.h b/config.def.h index 0d6d7a8983..45c99427d1 100644 --- a/config.def.h +++ b/config.def.h @@ -739,7 +739,9 @@ static const bool default_savefiles_in_content_dir = false; static const bool default_systemfiles_in_content_dir = false; static const bool default_screenshots_in_content_dir = false; -#if defined(_XBOX1) || defined(__PS3__) || defined(_XBOX360) || defined(DINGUX) +#if defined(RS90) +#define DEFAULT_MENU_TOGGLE_GAMEPAD_COMBO INPUT_TOGGLE_START_SELECT +#elif defined(_XBOX1) || defined(__PS3__) || defined(_XBOX360) || defined(DINGUX) #define DEFAULT_MENU_TOGGLE_GAMEPAD_COMBO INPUT_TOGGLE_L3_R3 #elif defined(PS2) || defined(PSP) #define DEFAULT_MENU_TOGGLE_GAMEPAD_COMBO INPUT_TOGGLE_HOLD_START diff --git a/configuration.c b/configuration.c index de23095dbc..f7f99b7b9f 100644 --- a/configuration.c +++ b/configuration.c @@ -70,6 +70,7 @@ enum video_driver_enum VIDEO_SDL, VIDEO_SDL2, VIDEO_SDL_DINGUX, + VIDEO_SDL_RS90, VIDEO_EXT, VIDEO_WII, VIDEO_WIIU, @@ -311,7 +312,11 @@ static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_SDL; #elif defined(HAVE_SDL2) static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_SDL2; #elif defined(HAVE_SDL_DINGUX) +#if defined(RS90) +static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_SDL_RS90; +#else static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_SDL_DINGUX; +#endif #elif defined(_WIN32) && !defined(_XBOX) static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_GDI; #elif defined(DJGPP) @@ -388,7 +393,9 @@ static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_EXT; static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_NULL; #endif -#if defined(PSP) || defined(EMSCRIPTEN) +#if defined(RS90) +static const enum audio_resampler_driver_enum AUDIO_DEFAULT_RESAMPLER_DRIVER = AUDIO_RESAMPLER_NEAREST; +#elif defined(PSP) || defined(EMSCRIPTEN) static const enum audio_resampler_driver_enum AUDIO_DEFAULT_RESAMPLER_DRIVER = AUDIO_RESAMPLER_CC; #else static const enum audio_resampler_driver_enum AUDIO_DEFAULT_RESAMPLER_DRIVER = AUDIO_RESAMPLER_SINC; @@ -852,6 +859,8 @@ const char *config_get_default_video(void) return "xvideo"; case VIDEO_SDL_DINGUX: return "sdl_dingux"; + case VIDEO_SDL_RS90: + return "sdl_rs90"; case VIDEO_SDL: return "sdl"; case VIDEO_SDL2: diff --git a/gfx/drivers/sdl_dingux_gfx.c b/gfx/drivers/sdl_dingux_gfx.c index 865c16f478..ae49b0d347 100644 --- a/gfx/drivers/sdl_dingux_gfx.c +++ b/gfx/drivers/sdl_dingux_gfx.c @@ -2,6 +2,7 @@ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen * Copyright (C) 2011-2017 - Daniel De Matteis * Copyright (C) 2011-2017 - Higor Euripedes + * Copyright (C) 2019-2021 - James Leaver * * 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- diff --git a/gfx/drivers/sdl_rs90_gfx.c b/gfx/drivers/sdl_rs90_gfx.c new file mode 100644 index 0000000000..77246a7e5f --- /dev/null +++ b/gfx/drivers/sdl_rs90_gfx.c @@ -0,0 +1,1187 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2011-2017 - Higor Euripedes + * Copyright (C) 2019-2021 - James Leaver + * Copyright (C) 2021 - John Parton + * + * 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 +#include +#include + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#ifdef HAVE_MENU +#include "../../menu/menu_driver.h" +#endif + +#include "../../dingux/dingux_utils.h" + +#include "../../verbosity.h" +#include "../../gfx/drivers_font_renderer/bitmap.h" +#include "../../configuration.h" +#include "../../retroarch.h" +#if defined(DINGUX_BETA) +#include "../../driver.h" +#endif + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#define SDL_RS90_WIDTH 240 +#define SDL_RS90_HEIGHT 160 + +#define SDL_RS90_NUM_FONT_GLYPHS 256 + +typedef struct sdl_rs90_video +{ + retro_time_t last_frame_time; + retro_time_t ff_frame_time_min; + SDL_Surface *screen; + bitmapfont_lut_t *osd_font; + /* Scaling/padding/cropping parameters */ + unsigned content_width; + unsigned content_height; + unsigned frame_width; + unsigned frame_height; + unsigned frame_padding_x; + unsigned frame_padding_y; + unsigned frame_crop_x; + unsigned frame_crop_y; +#if defined(DINGUX_BETA) + enum dingux_refresh_rate refresh_rate; +#endif + uint32_t font_colour32; + uint16_t font_colour16; + uint16_t menu_texture[SDL_RS90_WIDTH * SDL_RS90_HEIGHT]; + bool rgb32; + bool vsync; + bool keep_aspect; + bool scale_integer; + bool menu_active; + bool was_in_menu; + bool quitting; + bool mode_valid; +} sdl_rs90_video_t; + +static void sdl_rs90_init_font_color(sdl_rs90_video_t *vid) +{ + settings_t *settings = config_get_ptr(); + uint32_t red = 0xFF; + uint32_t green = 0xFF; + uint32_t blue = 0xFF; + + if (settings) + { + red = (uint32_t)((settings->floats.video_msg_color_r * 255.0f) + 0.5f) & 0xFF; + green = (uint32_t)((settings->floats.video_msg_color_g * 255.0f) + 0.5f) & 0xFF; + blue = (uint32_t)((settings->floats.video_msg_color_b * 255.0f) + 0.5f) & 0xFF; + } + + /* Convert to XRGB8888 */ + vid->font_colour32 = (red << 16) | (green << 8) | blue; + + /* Convert to RGB565 */ + red = red >> 3; + green = green >> 3; + blue = blue >> 3; + + vid->font_colour16 = (red << 11) | (green << 6) | blue; +} + +static void sdl_rs90_blit_text16( + sdl_rs90_video_t *vid, + unsigned x, unsigned y, + const char *str) +{ + /* Note: Cannot draw text in padding region + * (padding region is never cleared, so + * any text pixels would remain as garbage) */ + uint16_t *screen_buf = (uint16_t*)vid->screen->pixels; + bool **font_lut = vid->osd_font->lut; + /* 16 bit - divide pitch by 2 */ + uint16_t screen_stride = (uint16_t)(vid->screen->pitch >> 1); + uint16_t screen_width = vid->frame_width; + uint16_t screen_height = vid->frame_height; + unsigned x_pos = x + vid->frame_padding_x; + unsigned y_pos = (y > (screen_height >> 1)) ? + (y - vid->frame_padding_y) : (y + vid->frame_padding_y); + uint16_t shadow_color_buf[2] = {0}; + uint16_t color_buf[2]; + + color_buf[0] = vid->font_colour16; + color_buf[1] = 0; + + /* Check for out of bounds y coordinates */ + if (y_pos + FONT_HEIGHT + 1 >= + screen_height - vid->frame_padding_y) + return; + + while (!string_is_empty(str)) + { + /* Check for out of bounds x coordinates */ + if (x_pos + FONT_WIDTH_STRIDE + 1 >= + screen_width - vid->frame_padding_x) + return; + + /* Deal with spaces first, for efficiency */ + if (*str == ' ') + str++; + else + { + uint16_t i, j; + bool *symbol_lut; + uint32_t symbol = utf8_walk(&str); + + /* Stupid hack: 'oe' ligatures are not really + * standard extended ASCII, so we have to waste + * CPU cycles performing a conversion from the + * unicode values... */ + if (symbol == 339) /* Latin small ligature oe */ + symbol = 156; + if (symbol == 338) /* Latin capital ligature oe */ + symbol = 140; + + if (symbol >= SDL_RS90_NUM_FONT_GLYPHS) + continue; + + symbol_lut = font_lut[symbol]; + + for (j = 0; j < FONT_HEIGHT; j++) + { + uint32_t buff_offset = ((y_pos + j) * screen_stride) + x_pos; + + for (i = 0; i < FONT_WIDTH; i++) + { + if (*(symbol_lut + i + (j * FONT_WIDTH))) + { + uint16_t *screen_buf_ptr = screen_buf + buff_offset + i; + + /* Text pixel + right shadow */ + memcpy(screen_buf_ptr, color_buf, sizeof(uint16_t)); + + /* Bottom shadow */ + screen_buf_ptr += screen_stride; + memcpy(screen_buf_ptr, shadow_color_buf, sizeof(uint16_t)); + } + } + } + } + + x_pos += FONT_WIDTH_STRIDE; + } +} + +static void sdl_rs90_blit_text32( + sdl_rs90_video_t *vid, + unsigned x, unsigned y, + const char *str) +{ + /* Note: Cannot draw text in padding region + * (padding region is never cleared, so + * any text pixels would remain as garbage) */ + uint32_t *screen_buf = (uint32_t*)vid->screen->pixels; + bool **font_lut = vid->osd_font->lut; + /* 32 bit - divide pitch by 4 */ + uint32_t screen_stride = (uint32_t)(vid->screen->pitch >> 2); + uint32_t screen_width = vid->screen->w; + uint32_t screen_height = vid->screen->h; + unsigned x_pos = x + vid->frame_padding_x; + unsigned y_pos = (y > (screen_height >> 1)) ? + (y - vid->frame_padding_y) : (y + vid->frame_padding_y); + uint32_t shadow_color_buf[2] = {0}; + uint32_t color_buf[2]; + + color_buf[0] = vid->font_colour32; + color_buf[1] = 0; + + /* Check for out of bounds y coordinates */ + if (y_pos + FONT_HEIGHT + 1 >= + screen_height - vid->frame_padding_y) + return; + + while (!string_is_empty(str)) + { + /* Check for out of bounds x coordinates */ + if (x_pos + FONT_WIDTH_STRIDE + 1 >= + screen_width - vid->frame_padding_x) + return; + + /* Deal with spaces first, for efficiency */ + if (*str == ' ') + str++; + else + { + uint32_t i, j; + bool *symbol_lut; + uint32_t symbol = utf8_walk(&str); + + /* Stupid hack: 'oe' ligatures are not really + * standard extended ASCII, so we have to waste + * CPU cycles performing a conversion from the + * unicode values... */ + if (symbol == 339) /* Latin small ligature oe */ + symbol = 156; + if (symbol == 338) /* Latin capital ligature oe */ + symbol = 140; + + if (symbol >= SDL_RS90_NUM_FONT_GLYPHS) + continue; + + symbol_lut = font_lut[symbol]; + + for (j = 0; j < FONT_HEIGHT; j++) + { + uint32_t buff_offset = ((y_pos + j) * screen_stride) + x_pos; + + for (i = 0; i < FONT_WIDTH; i++) + { + if (*(symbol_lut + i + (j * FONT_WIDTH))) + { + uint32_t *screen_buf_ptr = screen_buf + buff_offset + i; + + /* Text pixel + right shadow */ + memcpy(screen_buf_ptr, color_buf, sizeof(uint32_t)); + + /* Bottom shadow */ + screen_buf_ptr += screen_stride; + memcpy(screen_buf_ptr, shadow_color_buf, sizeof(uint32_t)); + } + } + } + } + + x_pos += FONT_WIDTH_STRIDE; + } +} + +static void sdl_rs90_blit_video_mode_error_msg(sdl_rs90_video_t *vid) +{ + const char *error_msg = msg_hash_to_str(MSG_UNSUPPORTED_VIDEO_MODE); + char display_mode[64]; + + display_mode[0] = '\0'; + + /* Zero out pixel buffer */ + memset(vid->screen->pixels, 0, + vid->screen->pitch * vid->screen->h); + + /* Generate display mode string */ + snprintf(display_mode, sizeof(display_mode), "> %ux%u, %s", + vid->frame_width, vid->frame_height, + vid->rgb32 ? "XRGB8888" : "RGB565"); + + /* Print error message */ + if (vid->rgb32) + { + sdl_rs90_blit_text32(vid, + FONT_WIDTH_STRIDE, FONT_WIDTH_STRIDE, + error_msg); + + sdl_rs90_blit_text32(vid, + FONT_WIDTH_STRIDE, FONT_WIDTH_STRIDE + FONT_HEIGHT_STRIDE, + display_mode); + } + else + { + sdl_rs90_blit_text16(vid, + FONT_WIDTH_STRIDE, FONT_WIDTH_STRIDE, + error_msg); + + sdl_rs90_blit_text16(vid, + FONT_WIDTH_STRIDE, FONT_WIDTH_STRIDE + FONT_HEIGHT_STRIDE, + display_mode); + } +} + +static void sdl_rs90_gfx_free(void *data) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + + if (!vid) + return; + + if (vid->osd_font) + bitmapfont_free_lut(vid->osd_font); + + free(vid); +} + +static void sdl_rs90_input_driver_init( + const char *input_driver_name, const char *joypad_driver_name, + input_driver_t **input, void **input_data) +{ + /* Sanity check */ + if (!input || !input_data) + return; + + *input = NULL; + *input_data = NULL; + + /* If input driver name is empty, cannot + * initialise anything... */ + if (string_is_empty(input_driver_name)) + return; + + if (string_is_equal(input_driver_name, "sdl_dingux")) + { + *input_data = input_driver_init_wrap(&input_sdl_dingux, + joypad_driver_name); + + if (*input_data) + *input = &input_sdl_dingux; + + return; + } + +#if defined(HAVE_SDL) || defined(HAVE_SDL2) + if (string_is_equal(input_driver_name, "sdl")) + { + *input_data = input_driver_init_wrap(&input_sdl, + joypad_driver_name); + + if (*input_data) + *input = &input_sdl; + + return; + } +#endif + +#if defined(HAVE_UDEV) + if (string_is_equal(input_driver_name, "udev")) + { + *input_data = input_driver_init_wrap(&input_udev, + joypad_driver_name); + + if (*input_data) + *input = &input_udev; + + return; + } +#endif + +#if defined(__linux__) + if (string_is_equal(input_driver_name, "linuxraw")) + { + *input_data = input_driver_init_wrap(&input_linuxraw, + joypad_driver_name); + + if (*input_data) + *input = &input_linuxraw; + + return; + } +#endif +} + +static void *sdl_rs90_gfx_init(const video_info_t *video, + input_driver_t **input, void **input_data) +{ + sdl_rs90_video_t *vid = NULL; + uint32_t sdl_subsystem_flags = SDL_WasInit(0); + settings_t *settings = config_get_ptr(); +#if defined(DINGUX_BETA) + enum dingux_refresh_rate current_refresh_rate = DINGUX_REFRESH_RATE_60HZ; + enum dingux_refresh_rate target_refresh_rate = (enum dingux_refresh_rate) + settings->uints.video_dingux_refresh_rate; + bool refresh_rate_valid = false; + float hw_refresh_rate = 0.0f; +#endif + const char *input_driver_name = settings->arrays.input_driver; + const char *joypad_driver_name = settings->arrays.input_joypad_driver; + uint32_t surface_flags = (video->vsync) ? + (SDL_HWSURFACE | SDL_TRIPLEBUF | SDL_FULLSCREEN) : + (SDL_HWSURFACE | SDL_FULLSCREEN); + + /* Initialise graphics subsystem, if required */ + if (sdl_subsystem_flags == 0) + { + if (SDL_Init(SDL_INIT_VIDEO) < 0) + return NULL; + } + else if ((sdl_subsystem_flags & SDL_INIT_VIDEO) == 0) + { + if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) + return NULL; + } + + vid = (sdl_rs90_video_t*)calloc(1, sizeof(*vid)); + if (!vid) + return NULL; + +#if defined(DINGUX_BETA) + /* Get current refresh rate */ + refresh_rate_valid = dingux_get_video_refresh_rate(¤t_refresh_rate); + + /* Check if refresh rate needs to be updated */ + if (!refresh_rate_valid || + (current_refresh_rate != target_refresh_rate)) + hw_refresh_rate = dingux_set_video_refresh_rate(target_refresh_rate); + else + { + /* Correct refresh rate is already set, + * just convert to float */ + switch (current_refresh_rate) + { + case DINGUX_REFRESH_RATE_50HZ: + hw_refresh_rate = 50.0f; + break; + default: + hw_refresh_rate = 60.0f; + break; + } + } + + if (hw_refresh_rate == 0.0f) + { + RARCH_ERR("[SDL1]: Failed to set video refresh rate\n"); + goto error; + } + + vid->refresh_rate = target_refresh_rate; + switch (target_refresh_rate) + { + case DINGUX_REFRESH_RATE_50HZ: + vid->ff_frame_time_min = 20000; + break; + default: + vid->ff_frame_time_min = 16667; + break; + } + + driver_ctl(RARCH_DRIVER_CTL_SET_REFRESH_RATE, &hw_refresh_rate); +#else + vid->ff_frame_time_min = 16667; +#endif + + vid->screen = SDL_SetVideoMode( + SDL_RS90_WIDTH, SDL_RS90_HEIGHT, + video->rgb32 ? 32 : 16, + surface_flags); + + if (!vid->screen) + { + RARCH_ERR("[SDL1]: Failed to init SDL surface: %s\n", SDL_GetError()); + goto error; + } + + vid->content_width = SDL_RS90_WIDTH; + vid->content_height = SDL_RS90_HEIGHT; + vid->frame_width = SDL_RS90_WIDTH; + vid->frame_height = SDL_RS90_HEIGHT; + vid->rgb32 = video->rgb32; + vid->vsync = video->vsync; + vid->keep_aspect = settings->bools.video_dingux_ipu_keep_aspect; + vid->scale_integer = settings->bools.video_scale_integer; + vid->menu_active = false; + vid->was_in_menu = false; + vid->quitting = false; + vid->mode_valid = true; + vid->last_frame_time = 0; + + SDL_ShowCursor(SDL_DISABLE); + + sdl_rs90_input_driver_init(input_driver_name, + joypad_driver_name, input, input_data); + + /* Initialise OSD font */ + sdl_rs90_init_font_color(vid); + + vid->osd_font = bitmapfont_get_lut(); + + if (!vid->osd_font || + vid->osd_font->glyph_max < + (SDL_RS90_NUM_FONT_GLYPHS - 1)) + { + RARCH_ERR("[SDL1]: Failed to init OSD font\n"); + goto error; + } + + return vid; + +error: + sdl_rs90_gfx_free(vid); + return NULL; +} + +static void sdl_rs90_set_output( + sdl_rs90_video_t* vid, + unsigned width, unsigned height, bool rgb32) +{ + uint32_t surface_flags = (vid->vsync) ? + (SDL_HWSURFACE | SDL_TRIPLEBUF | SDL_FULLSCREEN) : + (SDL_HWSURFACE | SDL_FULLSCREEN); + + vid->content_width = width; + vid->content_height = height; + + /* Technically, "scale_integer" here just means "do not scale" + * If the content is larger, we crop, otherwise we just centre + * it in the frame. + * If we want to support a core with an absolutely tiny screen + * (i.e. less than 120x80), we should do actual integer scaling + * (PokeMini @ 96x64 and VeMUlator @ 48x32 are probably the + * only cores where this is an issue, but PokeMini at least + * offers internal upscaling...) */ + if (vid->scale_integer) + { + if (width > SDL_RS90_WIDTH) + { + vid->frame_width = SDL_RS90_WIDTH; + vid->frame_crop_x = (width - SDL_RS90_WIDTH) >> 1; + vid->frame_padding_x = 0; + } + else + { + vid->frame_width = width; + vid->frame_crop_x = 0; + vid->frame_padding_x = (SDL_RS90_WIDTH - width) >> 1; + } + + if (height > SDL_RS90_HEIGHT) + { + vid->frame_height = SDL_RS90_HEIGHT; + vid->frame_crop_y = (height - SDL_RS90_HEIGHT) >> 1; + vid->frame_padding_y = 0; + } + else + { + vid->frame_height = height; + vid->frame_crop_y = 0; + vid->frame_padding_y = (SDL_RS90_HEIGHT - height) >> 1; + } + } + else + { + /* Normal scaling */ + if (vid->keep_aspect) + { + if (height * SDL_RS90_WIDTH > width * SDL_RS90_HEIGHT) + { + /* Integer math is fine */ + vid->frame_width = (width * SDL_RS90_HEIGHT) / height; + vid->frame_height = SDL_RS90_HEIGHT; + } + else + { + /* Integer math is fine */ + vid->frame_width = SDL_RS90_WIDTH; + vid->frame_height = (height * SDL_RS90_WIDTH) / width; + } + } + else + { + vid->frame_width = SDL_RS90_WIDTH; + vid->frame_height = SDL_RS90_HEIGHT; + } + + vid->frame_crop_x = 0; + vid->frame_padding_x = (SDL_RS90_WIDTH - vid->frame_width) >> 1; + vid->frame_crop_y = 0; + vid->frame_padding_y = (SDL_RS90_HEIGHT - vid->frame_height) >> 1; + } + + /* Attempt to change video mode */ + vid->screen = SDL_SetVideoMode( + SDL_RS90_WIDTH, SDL_RS90_HEIGHT, + rgb32 ? 32 : 16, + surface_flags); + + /* Check whether selected display mode is valid */ + if (unlikely(!vid->screen)) + { + RARCH_ERR("[SDL1]: Failed to init SDL surface: %s\n", SDL_GetError()); + vid->mode_valid = false; + } + else + { + /* Determine whether frame padding is required */ + if ((vid->frame_padding_x > 0) || + (vid->frame_padding_y > 0)) + { + /* To prevent garbage pixels in the padding + * region, must zero out pixel buffer */ + if (SDL_MUSTLOCK(vid->screen)) + SDL_LockSurface(vid->screen); + + memset(vid->screen->pixels, 0, + vid->screen->pitch * vid->screen->h); + + if (SDL_MUSTLOCK(vid->screen)) + SDL_UnlockSurface(vid->screen); + } + + vid->mode_valid = true; + } +} + +/* Approximate nearest-neighbour scaling using + * bitshifts and integer math */ +static void sdl_rs90_blit_frame16_scale(sdl_rs90_video_t *vid, + uint16_t* src, unsigned width, unsigned height, + unsigned src_pitch) +{ + uint32_t x_step = (((uint32_t)(width) << 16) + 1) / vid->frame_width; + uint32_t y_step = (((uint32_t)(height) << 16) + 1) / vid->frame_height; + + /* 16 bit - divide pitch by 2 */ + size_t in_stride = (size_t)(src_pitch >> 1); + size_t out_stride = (size_t)(vid->screen->pitch >> 1); + + /* Apply x/y padding offset */ + uint16_t *top_corner = (uint16_t*)(vid->screen->pixels) + vid->frame_padding_x + + out_stride * vid->frame_padding_y; + + /* Temporary pointers */ + uint16_t *in_ptr = NULL; + uint16_t *out_ptr = NULL; + + uint32_t y = 0; + size_t row; + + /* TODO/FIXME: Optimize these loops further. + * Consider saving these computations in an array + * and indexing over them. + * Would likely be slower due to cache (non-)locality, + * but it's worth a shot. + * Tons of -> operations. */ + for (row = 0; row < vid->frame_height; row++) + { + size_t col = vid->frame_width; + uint32_t x = 0; + + out_ptr = top_corner + out_stride * row; + in_ptr = src + (y >> 16) * in_stride; + + do + { + *out_ptr = in_ptr[x >> 16]; + x += x_step; + out_ptr++; + } + while (--col); + + y += y_step; + } +} + +static void sdl_rs90_blit_frame16_no_scale(sdl_rs90_video_t *vid, + uint16_t* src, unsigned width, unsigned height, + unsigned src_pitch) +{ + /* 16 bit - divide pitch by 2 */ + size_t in_stride = (size_t)(src_pitch >> 1); + size_t out_stride = (size_t)(vid->screen->pitch >> 1); + + /* Manipulate offsets so that padding/crop + * are applied correctly */ + uint16_t *in_ptr = src + vid->frame_crop_x + vid->frame_crop_y * in_stride; + uint16_t *out_ptr = (uint16_t*)(vid->screen->pixels) + vid->frame_padding_x + + out_stride * vid->frame_padding_y; + + size_t y = vid->frame_height; + + /* TODO/FIXME: Optimize this loop */ + do + { + memcpy(out_ptr, in_ptr, vid->frame_width * sizeof(uint16_t)); + in_ptr += in_stride; + out_ptr += out_stride; + } + while (--y); +} + +static void sdl_rs90_blit_frame16(sdl_rs90_video_t *vid, + uint16_t* src, unsigned width, unsigned height, + unsigned src_pitch) +{ + /* If source and destination buffers have the + * same pitch, perform fast copy of raw pixel data */ + /* TODO/FIXME: Make sure this code path is used for + * GBA content */ + if (src_pitch == vid->screen->pitch && + height == SDL_RS90_HEIGHT) + memcpy(vid->screen->pixels, src, src_pitch * SDL_RS90_HEIGHT); + else + { + if (vid->scale_integer) + sdl_rs90_blit_frame16_no_scale( + vid, src, width, height, src_pitch); + else + sdl_rs90_blit_frame16_scale( + vid, src, width, height, src_pitch); + } +} + +static void sdl_rs90_blit_frame32_scale(sdl_rs90_video_t *vid, + uint32_t* src, unsigned width, unsigned height, + unsigned src_pitch) +{ + uint32_t x_step = (((uint32_t)(width) << 16) + 1) / vid->frame_width; + uint32_t y_step = (((uint32_t)(height) << 16) + 1) / vid->frame_height; + + /* 32 bit - divide pitch by 4 */ + size_t in_stride = (size_t)(src_pitch >> 2); + size_t out_stride = (size_t)(vid->screen->pitch >> 2); + + /* Apply x/y padding offset */ + uint32_t *top_corner = (uint32_t*)(vid->screen->pixels) + vid->frame_padding_x + + out_stride * vid->frame_padding_y; + + /* Temporary pointers */ + uint32_t *in_ptr = NULL; + uint32_t *out_ptr = NULL; + + uint32_t y = 0; + size_t row; + + /* TODO/FIXME: Optimize these loops further. + * Consider saving these computations in an array + * and indexing over them. + * Would likely be slower due to cache (non-)locality, + * but it's worth a shot. + * Tons of -> operations. */ + for (row = 0; row < vid->frame_height; row++) + { + size_t col = vid->frame_width; + uint32_t x = 0; + + out_ptr = top_corner + out_stride * row; + in_ptr = src + (y >> 16) * in_stride; + + do + { + *out_ptr = in_ptr[x >> 16]; + x += x_step; + out_ptr++; + } + while (--col); + + y += y_step; + } +} + +static void sdl_rs90_blit_frame32_no_scale(sdl_rs90_video_t *vid, + uint32_t* src, unsigned width, unsigned height, + unsigned src_pitch) +{ + /* 32 bit - divide pitch by 4 */ + size_t in_stride = (size_t)(src_pitch >> 2); + size_t out_stride = (size_t)(vid->screen->pitch >> 2); + + /* Manipulate offsets so that padding/crop + * are applied correctly */ + uint32_t *in_ptr = src + vid->frame_crop_x + vid->frame_crop_y * in_stride; + uint32_t *out_ptr = (uint32_t*)(vid->screen->pixels) + vid->frame_padding_x + + out_stride * vid->frame_padding_y; + + size_t y = vid->frame_height; + + /* TODO/FIXME: Optimize this loop */ + do + { + memcpy(out_ptr, in_ptr, vid->frame_width * sizeof(uint32_t)); + in_ptr += in_stride; + out_ptr += out_stride; + } + while (--y); +} + +static void sdl_rs90_blit_frame32(sdl_rs90_video_t *vid, + uint32_t* src, unsigned width, unsigned height, + unsigned src_pitch) +{ + /* If source and destination buffers have the + * same pitch, perform fast copy of raw pixel data */ + /* TODO/FIXME: Make sure this code path is used for + * GBA content */ + if ((src_pitch == vid->screen->pitch) && + (height == SDL_RS90_HEIGHT)) + memcpy(vid->screen->pixels, src, src_pitch * SDL_RS90_HEIGHT); + else + { + if (vid->scale_integer) + sdl_rs90_blit_frame32_no_scale( + vid, src, width, height, src_pitch); + else + sdl_rs90_blit_frame32_scale( + vid, src, width, height, src_pitch); + } +} + +static bool sdl_rs90_gfx_frame(void *data, const void *frame, + unsigned width, unsigned height, uint64_t frame_count, + unsigned pitch, const char *msg, video_frame_info_t *video_info) +{ + sdl_rs90_video_t* vid = (sdl_rs90_video_t*)data; + + /* Return early if: + * - Input sdl_rs90_video_t struct is NULL + * (cannot realistically happen) + * - Menu is inactive and input 'content' frame + * data is NULL (may happen when e.g. a running + * core skips a frame) */ + if (unlikely(!vid || (!frame && !vid->menu_active))) + return true; + + /* If fast forward is currently active, we may + * push frames at an 'unlimited' rate. Since the + * display has a fixed refresh rate of 60 Hz (or + * potentially 50 Hz on OpenDingux Beta), this + * represents wasted effort. We therefore drop any + * 'excess' frames in this case. + * (Note that we *only* do this when fast forwarding. + * Attempting this trick while running content normally + * will cause bad frame pacing) */ + if (unlikely(video_info->input_driver_nonblock_state)) + { + retro_time_t current_time = cpu_features_get_time_usec(); + + if ((current_time - vid->last_frame_time) < + vid->ff_frame_time_min) + return true; + + vid->last_frame_time = current_time; + } + +#ifdef HAVE_MENU + menu_driver_frame(video_info->menu_is_alive, video_info); +#endif + + if (likely(!vid->menu_active)) + { + /* Update video mode if we were in the menu on + * the previous frame, or width/height have changed */ + if (unlikely( + vid->was_in_menu || + (vid->content_width != width) || + (vid->content_height != height))) + sdl_rs90_set_output(vid, width, height, vid->rgb32); + + /* Must always lock SDL surface before + * manipulating raw pixel buffer */ + if (SDL_MUSTLOCK(vid->screen)) + SDL_LockSurface(vid->screen); + + if (likely(vid->mode_valid)) + { + /* Blit frame to SDL surface */ + if (vid->rgb32) + sdl_rs90_blit_frame32(vid, (uint32_t*)frame, + width, height, pitch); + else + sdl_rs90_blit_frame16(vid, (uint16_t*)frame, + width, height, pitch); + } + /* If current display mode is invalid, + * just display an error message */ + else + sdl_rs90_blit_video_mode_error_msg(vid); + + vid->was_in_menu = false; + } + else + { + /* If this is the first frame that the menu + * is active, update video mode */ + if (!vid->was_in_menu) + { + sdl_rs90_set_output(vid, + SDL_RS90_WIDTH, SDL_RS90_HEIGHT, false); + + vid->was_in_menu = true; + } + + if (SDL_MUSTLOCK(vid->screen)) + SDL_LockSurface(vid->screen); + + /* Blit menu texture to SDL surface */ + sdl_rs90_blit_frame16(vid, vid->menu_texture, + SDL_RS90_WIDTH, SDL_RS90_HEIGHT, + SDL_RS90_WIDTH * sizeof(uint16_t)); + } + + /* Print OSD text, if required */ + if (msg) + { + /* If menu is active, colour depth is overridden + * to 16 bit */ + if (vid->rgb32 && !vid->menu_active) + sdl_rs90_blit_text32(vid, FONT_WIDTH_STRIDE, + vid->screen->h - (FONT_HEIGHT + FONT_WIDTH_STRIDE), msg); + else + sdl_rs90_blit_text16(vid, FONT_WIDTH_STRIDE, + vid->screen->h - (FONT_HEIGHT + FONT_WIDTH_STRIDE), msg); + } + + /* Pixel manipulation complete - unlock + * SDL surface */ + if (SDL_MUSTLOCK(vid->screen)) + SDL_UnlockSurface(vid->screen); + + SDL_Flip(vid->screen); + + return true; +} + +static void sdl_rs90_set_texture_enable(void *data, bool state, bool full_screen) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + + if (unlikely(!vid)) + return; + + vid->menu_active = state; +} + +static void sdl_rs90_set_texture_frame(void *data, const void *frame, bool rgb32, + unsigned width, unsigned height, float alpha) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + + if (unlikely( + !vid || + rgb32 || + (width > SDL_RS90_WIDTH) || + (height > SDL_RS90_HEIGHT))) + return; + + memcpy(vid->menu_texture, frame, width * height * sizeof(uint16_t)); +} + +static void sdl_rs90_gfx_set_nonblock_state(void *data, bool toggle, + bool adaptive_vsync_enabled, unsigned swap_interval) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + bool vsync = !toggle; + + if (unlikely(!vid)) + return; + + /* Check whether vsync status has changed */ + if (vid->vsync != vsync) + { + unsigned current_width = vid->content_width; + unsigned current_height = vid->content_height; + vid->vsync = vsync; + + /* Update video mode */ + + /* TODO/FIXME: The following workaround is required + * on GCW0 devices; check whether it is required on + * the RS-90, and remove if not */ + + /* Note that a tedious workaround is required... + * - Calling SDL_SetVideoMode() with the currently + * set width, height and pixel format can randomly + * become a noop even if the surface flags change. + * - Since all we are doing here is changing the VSYNC + * parameter (which just modifies surface flags), this + * means the VSYNC toggle may not be registered... + * - This is a huge problem when enabling fast forward, + * because VSYNC ON effectively limits maximum frame + * rate - if we push frames too rapidly, the OS chokes + * and the display freezes. + * We have to ensure that the VSYNC state change is + * applied in all cases. We can only do this by forcing + * a 'real' video mode update, which means adjusting the + * video resolution. We therefore end up calling + * sdl_rs90_set_output() *twice*, setting the dimensions + * to an arbitrary value before restoring the actual + * desired width/height */ + sdl_rs90_set_output(vid, + current_width, + (current_height > 4) ? (current_height - 2) : 16, + vid->rgb32); + + sdl_rs90_set_output(vid, + current_width, current_height, vid->rgb32); + } +} + +static void sdl_rs90_gfx_check_window(sdl_rs90_video_t *vid) +{ + SDL_Event event; + + SDL_PumpEvents(); + while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_QUITMASK)) + { + if (event.type != SDL_QUIT) + continue; + + vid->quitting = true; + break; + } +} + +static bool sdl_rs90_gfx_alive(void *data) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + + if (unlikely(!vid)) + return false; + + sdl_rs90_gfx_check_window(vid); + return !vid->quitting; +} + +static bool sdl_rs90_gfx_focus(void *data) +{ + return true; +} + +static bool sdl_rs90_gfx_suppress_screensaver(void *data, bool enable) +{ + return false; +} + +static bool sdl_rs90_gfx_has_windowed(void *data) +{ + return false; +} + +static void sdl_rs90_gfx_viewport_info(void *data, struct video_viewport *vp) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + + if (unlikely(!vid)) + return; + + vp->x = 0; + vp->y = 0; + vp->width = vp->full_width = vid->frame_width; + vp->height = vp->full_height = vid->frame_height; +} + +static float sdl_rs90_get_refresh_rate(void *data) +{ +#if defined(DINGUX_BETA) + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + + if (!vid) + return 0.0f; + + switch (vid->refresh_rate) + { + case DINGUX_REFRESH_RATE_50HZ: + return 50.0f; + default: + break; + } +#endif + + return 60.0f; +} + +static void sdl_rs90_apply_state_changes(void *data) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + settings_t *settings = config_get_ptr(); + bool keep_aspect = (settings) ? settings->bools.video_dingux_ipu_keep_aspect : true; + bool integer_scaling = (settings) ? settings->bools.video_scale_integer : false; + + if (!vid || !settings) + return; + + if ((vid->keep_aspect != keep_aspect) || + (vid->scale_integer != integer_scaling)) + { + vid->keep_aspect = keep_aspect; + vid->scale_integer = integer_scaling; + + /* Aspect/scaling changes require all frame + * dimension/padding/cropping parameters to + * be recalculated. Easiest method is to just + * (re-)set the current output video mode */ + sdl_rs90_set_output(vid, vid->content_width, + vid->content_height, vid->rgb32); + } +} + +static uint32_t sdl_rs90_get_flags(void *data) +{ + return 0; +} + +static const video_poke_interface_t sdl_rs90_poke_interface = { + sdl_rs90_get_flags, + NULL, + NULL, + NULL, + sdl_rs90_get_refresh_rate, + NULL, /* set_filtering */ + NULL, /* get_video_output_size */ + NULL, /* get_video_output_prev */ + NULL, /* get_video_output_next */ + NULL, /* get_current_framebuffer */ + NULL, /* get_proc_address */ + NULL, + sdl_rs90_apply_state_changes, + sdl_rs90_set_texture_frame, + sdl_rs90_set_texture_enable, + NULL, + NULL, /* sdl_show_mouse */ + NULL, /* sdl_grab_mouse_toggle */ + NULL, /* get_current_shader */ + NULL, /* get_current_software_framebuffer */ + NULL /* get_hw_render_interface */ +}; + +static void sdl_rs90_get_poke_interface(void *data, const video_poke_interface_t **iface) +{ + *iface = &sdl_rs90_poke_interface; +} + +static bool sdl_rs90_gfx_set_shader(void *data, + enum rarch_shader_type type, const char *path) +{ + return false; +} + +video_driver_t video_sdl_rs90 = { + sdl_rs90_gfx_init, + sdl_rs90_gfx_frame, + sdl_rs90_gfx_set_nonblock_state, + sdl_rs90_gfx_alive, + sdl_rs90_gfx_focus, + sdl_rs90_gfx_suppress_screensaver, + sdl_rs90_gfx_has_windowed, + sdl_rs90_gfx_set_shader, + sdl_rs90_gfx_free, + "sdl_rs90", + NULL, + NULL, /* set_rotation */ + sdl_rs90_gfx_viewport_info, + NULL, /* read_viewport */ + NULL, /* read_frame_raw */ +#ifdef HAVE_OVERLAY + NULL, +#endif +#ifdef HAVE_VIDEO_LAYOUT + NULL, +#endif + sdl_rs90_get_poke_interface +}; diff --git a/griffin/griffin.c b/griffin/griffin.c index e60461a0ca..a187296e3b 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -467,6 +467,14 @@ VIDEO DRIVER #include "../gfx/common/sdl2_common.c" #endif +#if defined(DINGUX) && defined(HAVE_SDL_DINGUX) +#if defined(RS90) +#include "../gfx/drivers/sdl_rs90_gfx.c" +#else +#include "../gfx/drivers/sdl_dingux_gfx.c" +#endif +#endif + #ifdef HAVE_VG #include "../gfx/drivers/vg.c" #endif diff --git a/input/drivers_joypad/sdl_dingux_joypad.c b/input/drivers_joypad/sdl_dingux_joypad.c index 4b74166a40..8406390660 100644 --- a/input/drivers_joypad/sdl_dingux_joypad.c +++ b/input/drivers_joypad/sdl_dingux_joypad.c @@ -31,6 +31,11 @@ #include "../../configuration.h" #endif +#if !defined(RS90) +#define SDL_DINGUX_HAS_ANALOG 1 +#define SDL_DINGUX_HAS_MENU_TOGGLE 1 +#endif + /* Simple joypad driver designed to rationalise * the bizarre keyboard/gamepad hybrid setup * of OpenDingux devices */ @@ -66,7 +71,9 @@ typedef struct typedef struct { +#if defined(SDL_DINGUX_HAS_ANALOG) SDL_Joystick *device; +#endif #if defined(HAVE_LIBSHAKE) dingux_joypad_rumble_t rumble; #endif @@ -74,11 +81,15 @@ typedef struct uint16_t pad_state; int16_t analog_state[2][2]; bool connected; +#if defined(SDL_DINGUX_HAS_MENU_TOGGLE) bool menu_toggle; +#endif } dingux_joypad_t; +#if defined(SDL_DINGUX_HAS_MENU_TOGGLE) /* TODO/FIXME - global referenced outside */ extern uint64_t lifecycle_state; +#endif static dingux_joypad_t dingux_joypad; @@ -259,6 +270,7 @@ static void sdl_dingux_joypad_connect(void) { dingux_joypad_t *joypad = (dingux_joypad_t*)&dingux_joypad; +#if defined(SDL_DINGUX_HAS_ANALOG) /* Open joypad device */ if (SDL_NumJoysticks() > 0) joypad->device = SDL_JoystickOpen(0); @@ -266,6 +278,7 @@ static void sdl_dingux_joypad_connect(void) /* If joypad exists, get number of axes */ if (joypad->device) joypad->num_axes = SDL_JoystickNumAxes(joypad->device); +#endif #if defined(HAVE_LIBSHAKE) /* Configure rumble interface */ @@ -289,8 +302,10 @@ static void sdl_dingux_joypad_disconnect(void) { dingux_joypad_t *joypad = (dingux_joypad_t*)&dingux_joypad; +#if defined(SDL_DINGUX_HAS_ANALOG) if (joypad->device) SDL_JoystickClose(joypad->device); +#endif if (joypad->connected) input_autoconfigure_disconnect(0, sdl_dingux_joypad.ident); @@ -329,7 +344,9 @@ static void sdl_dingux_joypad_destroy(void) Shake_Quit(); #endif +#if defined(SDL_DINGUX_HAS_MENU_TOGGLE) BIT64_CLEAR(lifecycle_state, RARCH_MENU_TOGGLE); +#endif } static void *sdl_dingux_joypad_init(void *data) @@ -338,8 +355,11 @@ static void *sdl_dingux_joypad_init(void *data) uint32_t sdl_subsystem_flags = SDL_WasInit(0); memset(joypad, 0, sizeof(dingux_joypad_t)); +#if defined(SDL_DINGUX_HAS_MENU_TOGGLE) BIT64_CLEAR(lifecycle_state, RARCH_MENU_TOGGLE); +#endif +#if defined(SDL_DINGUX_HAS_ANALOG) /* Initialise joystick subsystem, if required */ if (sdl_subsystem_flags == 0) { @@ -351,6 +371,7 @@ static void *sdl_dingux_joypad_init(void *data) if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) return NULL; } +#endif #if defined(HAVE_LIBSHAKE) /* Initialise rumble interface */ @@ -397,6 +418,7 @@ static void sdl_dingux_joypad_get_buttons(unsigned port, input_bits_t *state) static int16_t sdl_dingux_joypad_axis_state(unsigned port, uint32_t joyaxis) { +#if defined(SDL_DINGUX_HAS_ANALOG) dingux_joypad_t *joypad = (dingux_joypad_t*)&dingux_joypad; int val = 0; int axis = -1; @@ -437,6 +459,9 @@ static int16_t sdl_dingux_joypad_axis_state(unsigned port, uint32_t joyaxis) return 0; return val; +#else + return 0; +#endif } static int16_t sdl_dingux_joypad_axis(unsigned port, uint32_t joyaxis) @@ -465,16 +490,20 @@ static int16_t sdl_dingux_joypad_state( /* Auto-binds are per joypad, not per user. */ const uint64_t joykey = (binds[i].joykey != NO_BTN) ? binds[i].joykey : joypad_info->auto_binds[i].joykey; +#if defined(SDL_DINGUX_HAS_ANALOG) const uint32_t joyaxis = (binds[i].joyaxis != AXIS_NONE) ? binds[i].joyaxis : joypad_info->auto_binds[i].joyaxis; - - if ((uint16_t)joykey != NO_BTN && +#endif + + if ((uint16_t)joykey != NO_BTN && (joypad->pad_state & (1 << (uint16_t)joykey))) ret |= (1 << i); +#if defined(SDL_DINGUX_HAS_ANALOG) else if (joyaxis != AXIS_NONE && - ((float)abs(sdl_dingux_joypad_axis_state(port_idx, joyaxis)) + ((float)abs(sdl_dingux_joypad_axis_state(port_idx, joyaxis)) / 0x8000) > joypad_info->axis_threshold) ret |= (1 << i); +#endif } return ret; @@ -485,6 +514,7 @@ static void sdl_dingux_joypad_poll(void) dingux_joypad_t *joypad = (dingux_joypad_t*)&dingux_joypad; SDL_Event event; +#if defined(SDL_DINGUX_HAS_MENU_TOGGLE) /* Note: The menu toggle key is an awkward special * case - the press/release events happen almost * instantaneously, and since we only sample once @@ -496,6 +526,7 @@ static void sdl_dingux_joypad_poll(void) BIT64_CLEAR(lifecycle_state, RARCH_MENU_TOGGLE); joypad->menu_toggle = false; } +#endif /* All digital inputs map to keyboard keys * - X: SDLK_SPACE @@ -571,10 +602,12 @@ static void sdl_dingux_joypad_poll(void) case SDLK_LEFT: BIT16_SET(joypad->pad_state, RETRO_DEVICE_ID_JOYPAD_LEFT); break; +#if defined(SDL_DINGUX_HAS_MENU_TOGGLE) case SDLK_HOME: BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE); joypad->menu_toggle = true; break; +#endif default: break; } @@ -639,6 +672,7 @@ static void sdl_dingux_joypad_poll(void) } } +#if defined(SDL_DINGUX_HAS_ANALOG) /* Analog inputs come from the joypad device, * if connected */ if (joypad->device) @@ -676,6 +710,7 @@ static void sdl_dingux_joypad_poll(void) (axis_value < -0x7FFF) ? -0x7FFF : axis_value; } } +#endif } input_device_driver_t sdl_dingux_joypad = { diff --git a/libretro-common/rthreads/rthreads.c b/libretro-common/rthreads/rthreads.c index bb5b38b037..3942651532 100644 --- a/libretro-common/rthreads/rthreads.c +++ b/libretro-common/rthreads/rthreads.c @@ -872,7 +872,7 @@ bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us) int tickms = ps2_clock(); now.tv_sec = tickms/1000; now.tv_nsec = tickms * 1000; -#elif defined(__mips__) || defined(VITA) || defined(_3DS) +#elif !defined(DINGUX_BETA) && (defined(__mips__) || defined(VITA) || defined(_3DS)) struct timeval tm; gettimeofday(&tm, NULL); diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index ff8631edeb..522c03b778 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -80,6 +80,22 @@ #define RGUI_MIN_FB_WIDTH 256 #define RGUI_MAX_FB_WIDTH 426 +#if defined(DINGUX) +#if defined(RS90) +/* The RS-90 uses a fixed framebuffer size + * of 240x160 */ +#define RGUI_DINGUX_ASPECT_RATIO RGUI_ASPECT_RATIO_3_2 +#define RGUI_DINGUX_FB_WIDTH 240 +#define RGUI_DINGUX_FB_HEIGHT 160 +#else +/* Other Dingux devices (RG350 etc.) use a + * fixed framebuffer size of 320x240 */ +#define RGUI_DINGUX_ASPECT_RATIO RGUI_ASPECT_RATIO_4_3 +#define RGUI_DINGUX_FB_WIDTH 320 +#define RGUI_DINGUX_FB_HEIGHT 240 +#endif +#endif + /* Maximum entry value length in characters * when using fixed with layouts * (i.e. Maximum possible 'spacing' as @@ -1502,20 +1518,21 @@ static bool rgui_set_pixel_format_function(void) return transparency_supported; } - if ( string_is_equal(driver_ident, "ps2")) /* PS2 */ + if ( string_is_equal(driver_ident, "ps2")) /* PS2 */ { argb32_to_pixel_platform_format = argb32_to_abgr1555; transparency_supported = false; } - else if (string_is_equal(driver_ident, "gx")) /* GEKKO */ + else if (string_is_equal(driver_ident, "gx")) /* GEKKO */ argb32_to_pixel_platform_format = argb32_to_rgb5a3; - else if (string_is_equal(driver_ident, "psp1")) /* PSP */ + else if (string_is_equal(driver_ident, "psp1")) /* PSP */ argb32_to_pixel_platform_format = argb32_to_abgr4444; - else if (string_is_equal(driver_ident, "d3d10") || /* D3D10/11/12 */ + else if (string_is_equal(driver_ident, "d3d10") || /* D3D10/11/12 */ string_is_equal(driver_ident, "d3d11") || string_is_equal(driver_ident, "d3d12")) argb32_to_pixel_platform_format = argb32_to_bgra4444; - else if (string_is_equal(driver_ident, "sdl_dingux")) /* DINGUX SDL */ + else if (string_is_equal(driver_ident, "sdl_dingux") || /* DINGUX SDL */ + string_is_equal(driver_ident, "sdl_rs90")) { argb32_to_pixel_platform_format = argb32_to_rgb565; transparency_supported = false; @@ -3006,7 +3023,7 @@ static void load_custom_theme(rgui_t *rgui, rgui_theme_t *theme_colors, const ch const char *wallpaper_key = NULL; bool success = false; #if defined(DINGUX) - unsigned aspect_ratio = RGUI_ASPECT_RATIO_4_3; + unsigned aspect_ratio = RGUI_DINGUX_ASPECT_RATIO; #else settings_t *settings = config_get_ptr(); unsigned aspect_ratio = settings->uints.menu_rgui_aspect_ratio; @@ -5435,15 +5452,14 @@ static bool rgui_set_aspect_ratio(rgui_t *rgui, * width value must be zero... */ unsigned max_frame_buf_width = 424; #elif defined(DINGUX) - /* Dingux devices use a fixed framebuffer size - * of 320x240 */ - unsigned max_frame_buf_width = 320; + /* Dingux devices use a fixed framebuffer size */ + unsigned max_frame_buf_width = RGUI_DINGUX_FB_WIDTH; #else struct video_viewport vp; unsigned max_frame_buf_width = RGUI_MAX_FB_WIDTH; #endif #if defined(DINGUX) - unsigned aspect_ratio = RGUI_ASPECT_RATIO_4_3; + unsigned aspect_ratio = RGUI_DINGUX_ASPECT_RATIO; unsigned aspect_ratio_lock = RGUI_ASPECT_RATIO_LOCK_NONE; #else settings_t *settings = config_get_ptr(); @@ -5469,9 +5485,8 @@ static bool rgui_set_aspect_ratio(rgui_t *rgui, * values */ rgui->frame_buf.height = p_disp->framebuf_height; #elif defined(DINGUX) - /* Dingux devices use a fixed framebuffer size - * of 320x240 */ - rgui->frame_buf.height = 240; + /* Dingux devices use a fixed framebuffer size */ + rgui->frame_buf.height = RGUI_DINGUX_FB_HEIGHT; #else /* If window height is less than RGUI default * height of 240, allow the frame buffer to @@ -6587,7 +6602,7 @@ static void rgui_frame(void *data, video_frame_info_t *video_info) bool bg_filler_thickness_enable = settings->bools.menu_rgui_background_filler_thickness_enable; bool border_filler_thickness_enable = settings->bools.menu_rgui_border_filler_thickness_enable; #if defined(DINGUX) - unsigned aspect_ratio = RGUI_ASPECT_RATIO_4_3; + unsigned aspect_ratio = RGUI_DINGUX_ASPECT_RATIO; unsigned aspect_ratio_lock = RGUI_ASPECT_RATIO_LOCK_NONE; #else unsigned aspect_ratio = settings->uints.menu_rgui_aspect_ratio; @@ -6714,7 +6729,7 @@ static void rgui_frame(void *data, video_frame_info_t *video_info) if ((rgui->window_width != video_width) || (rgui->window_height != video_height)) { -#if !defined(GEKKO) +#if !defined(GEKKO) && !defined(DINGUX) /* If window width or height are less than the * RGUI default size of (320-426)x240, must enable * dynamic menu 'downscaling'. @@ -6744,7 +6759,6 @@ static void rgui_frame(void *data, video_frame_info_t *video_info) case RGUI_ASPECT_RATIO_5_3_CENTRE: default_fb_width = 400; break; - default: /* 4:3 */ default_fb_width = 320; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 00805b4f5c..c972e8696b 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -7768,7 +7768,8 @@ unsigned menu_displaylist_build_list( case DISPLAYLIST_VIDEO_SCALING_SETTINGS_LIST: { #if defined(DINGUX) - if (string_is_equal(settings->arrays.video_driver, "sdl_dingux")) + if (string_is_equal(settings->arrays.video_driver, "sdl_dingux") || + string_is_equal(settings->arrays.video_driver, "sdl_rs90")) { if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER, diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 19631ad7a3..ca7aad473e 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -10954,7 +10954,8 @@ static bool setting_append_list( } #if defined(DINGUX) && defined(DINGUX_BETA) - if (string_is_equal(settings->arrays.video_driver, "sdl_dingux")) + if (string_is_equal(settings->arrays.video_driver, "sdl_dingux") || + string_is_equal(settings->arrays.video_driver, "sdl_rs90")) { CONFIG_UINT( list, list_info, @@ -11209,7 +11210,8 @@ static bool setting_append_list( SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_LAKKA_ADVANCED); #if defined(DINGUX) - if (string_is_equal(settings->arrays.video_driver, "sdl_dingux")) + if (string_is_equal(settings->arrays.video_driver, "sdl_dingux") || + string_is_equal(settings->arrays.video_driver, "sdl_rs90")) { CONFIG_BOOL( list, list_info, @@ -14935,10 +14937,11 @@ static bool setting_append_list( general_read_handler); MENU_SETTINGS_LIST_CURRENT_ADD_VALUES(list, list_info, "cfg"); - /* ps2 and sdl_dingux gfx drivers do not support - * menu framebuffer transparency */ + /* ps2 and sdl_dingux/sdl_rs90 gfx drivers do + * not support menu framebuffer transparency */ if (!string_is_equal(settings->arrays.video_driver, "ps2") && - !string_is_equal(settings->arrays.video_driver, "sdl_dingux")) + !string_is_equal(settings->arrays.video_driver, "sdl_dingux") && + !string_is_equal(settings->arrays.video_driver, "sdl_rs90")) { CONFIG_BOOL( list, list_info, diff --git a/retroarch.h b/retroarch.h index 8dde537f69..d49dca46cd 100644 --- a/retroarch.h +++ b/retroarch.h @@ -1874,6 +1874,7 @@ extern video_driver_t video_xvideo; extern video_driver_t video_sdl; extern video_driver_t video_sdl2; extern video_driver_t video_sdl_dingux; +extern video_driver_t video_sdl_rs90; extern video_driver_t video_vg; extern video_driver_t video_omap; extern video_driver_t video_exynos; diff --git a/retroarch_data.h b/retroarch_data.h index 22d74a3406..b48ace713d 100644 --- a/retroarch_data.h +++ b/retroarch_data.h @@ -645,8 +645,12 @@ static const video_driver_t *video_drivers[] = { &video_sdl2, #endif #ifdef HAVE_SDL_DINGUX +#if defined(RS90) + &video_sdl_rs90, +#else &video_sdl_dingux, #endif +#endif #ifdef HAVE_XVIDEO &video_xvideo, #endif @@ -995,7 +999,7 @@ static input_device_driver_t *joypad_drivers[] = { }; #ifdef HAVE_HID -static bool null_hid_joypad_query(void *data, unsigned pad) { +static bool null_hid_joypad_query(void *data, unsigned pad) { return pad < MAX_USERS; } static const char *null_hid_joypad_name( void *data, unsigned pad) { return NULL; } @@ -1665,7 +1669,7 @@ typedef struct discord_state discord_state_t; #endif struct runloop -{ +{ retro_usec_t frame_time_last; /* int64_t alignment */ msg_queue_t msg_queue; /* ptr alignment */ @@ -1733,7 +1737,7 @@ struct rarch_state menu_input_t menu_input_state; /* retro_time_t alignment */ #endif - + #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) rarch_timer_t shader_delay_timer; /* int64_t alignment */ @@ -1911,7 +1915,7 @@ struct rarch_state struct retro_subsystem_rom_info subsystem_data_roms[SUBSYSTEM_MAX_SUBSYSTEMS] [SUBSYSTEM_MAX_SUBSYSTEM_ROMS]; /* ptr alignment */ - + gfx_ctx_driver_t current_video_context; /* ptr alignment */ content_state_t content_st; /* ptr alignment */ midi_event_t midi_drv_input_event; /* ptr alignment */ @@ -1989,7 +1993,7 @@ struct rarch_state size_t runahead_save_state_size; #endif - jmp_buf error_sjlj_context; /* 4-byte alignment, + jmp_buf error_sjlj_context; /* 4-byte alignment, put it right before long */ turbo_buttons_t input_driver_turbo_btns; /* int32_t alignment */ @@ -2017,7 +2021,7 @@ struct rarch_state int reannounce; #endif - input_device_info_t input_device_info[MAX_INPUT_DEVICES]; + input_device_info_t input_device_info[MAX_INPUT_DEVICES]; /* unsigned alignment */ #ifdef HAVE_MENU menu_dialog_t dialog_st; /* unsigned alignment */ @@ -2093,7 +2097,7 @@ struct rarch_state #endif #ifdef HAVE_MENU - menu_input_pointer_hw_state_t menu_input_pointer_hw_state; + menu_input_pointer_hw_state_t menu_input_pointer_hw_state; /* int16_t alignment */ #endif