From 6d2a7b1f26a2d10e10f442d9103599f11c5c3b24 Mon Sep 17 00:00:00 2001 From: misson20000 Date: Sat, 23 Dec 2017 17:26:58 -0800 Subject: [PATCH] Nintendo Switch (libtransistor) port --- Makefile.common | 6 + Makefile.switch | 68 ++++++ config.def.h | 1 + configuration.c | 15 ++ gfx/drivers/switch_gfx.c | 271 ++++++++++++++++++++++++ gfx/video_driver.c | 3 + gfx/video_driver.h | 1 + input/drivers/switch_input.c | 138 ++++++++++++ input/drivers_joypad/switch_joypad.c | 155 ++++++++++++++ input/input_driver.c | 6 + input/input_driver.h | 2 + libretro-common/features/features_cpu.c | 7 + libretro-common/include/memmap.h | 2 +- 13 files changed, 674 insertions(+), 1 deletion(-) create mode 100644 Makefile.switch create mode 100644 gfx/drivers/switch_gfx.c create mode 100644 input/drivers/switch_input.c create mode 100644 input/drivers_joypad/switch_joypad.c diff --git a/Makefile.common b/Makefile.common index 41a54ef570..3ecacbbcd6 100644 --- a/Makefile.common +++ b/Makefile.common @@ -870,6 +870,12 @@ ifeq ($(TARGET), retroarch_3ds) input/drivers_joypad/ctr_joypad.o endif +ifeq ($(TARGET), retroarch_switch) + OBJ += gfx/drivers/switch_gfx.o \ + input/drivers/switch_input.o \ + input/drivers_joypad/switch_joypad.o +endif + ifeq ($(HAVE_WAYLAND), 1) OBJ += gfx/drivers_context/wayland_ctx.o \ input/drivers/wayland_input.o diff --git a/Makefile.switch b/Makefile.switch new file mode 100644 index 0000000000..a22af46912 --- /dev/null +++ b/Makefile.switch @@ -0,0 +1,68 @@ +TARGET := retroarch_switch + +DEBUG ?= 0 +GRIFFIN_BUILD = 0 +WHOLE_ARCHIVE_LINK = 0 + +OBJ := + +DEFINES := -DSWITCH=1 -U__linux__ -U__linux + +ifeq ($(GRIFFIN_BUILD), 1) + OBJ += griffin/griffin.o + DEFINES += -DHAVE_GRIFFIN=1 -DHAVE_NEON -DHAVE_MATERIALUI -DHAVE_LIBRETRODB -DHAVE_CC_RESAMPLER + DEFINES += -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DWANT_ZLIB +else + HAVE_CC_RESAMPLER = 1 + HAVE_MENU_COMMON = 0 + HAVE_RTGA = 1 + HAVE_RPNG = 1 + HAVE_RJPEG = 1 + HAVE_RBMP = 1 + HAVE_RGUI = 0 + HAVE_ZLIB = 1 + HAVE_BUILTINZLIB = 1 + HAVE_LIBRETRODB = 1 + HAVE_ZARCH = 0 + HAVE_MATERIALUI = 0 # enable later? + HAVE_XMB = 0 + HAVE_STATIC_VIDEO_FILTERS = 1 + HAVE_STATIC_AUDIO_FILTERS = 1 + HAVE_MENU = 0 + + include Makefile.common + BLACKLIST := + BLACKLIST += input/input_overlay.o + BLACKLIST += tasks/task_overlay.o + OBJ := $(filter-out $(BLACKLIST),$(OBJ)) +endif + + +ifeq ($(strip $(LIBTRANSISTOR_HOME)),) +$(error "Please set LIBTRANSISTOR_HOME in your environment. export LIBTRANSISTOR_HOME=o libtransistor") +endif + +include $(LIBTRANSISTOR_HOME)/libtransistor.mk + +INCDIRS := -I. -Ideps/libz -Ilibretro-common/include -Ideps/stb -I$(LIBTRANSISTOR_HOME)/build/sdl2_install/include/SDL2/ +LIBDIRS := -L. + +TARGETS := $(TARGET).nro + +CFLAGS += $(INCDIRS) $(DEFINES) -Wunused-command-line-argument + +all: $(TARGETS) + +$(TARGET).nro.so: $(OBJ) libretro_switch.a fs.squashfs.o $(LIBTRANSISTOR_NRO_LIB) $(LIBTRANSISTOR_COMMON_LIBS) + $(LD) $(LD_FLAGS) --allow-multiple-definition -o $@ $(OBJ) libretro_switch.a fs.squashfs.o $(LIBTRANSISTOR_NRO_LDFLAGS) -lm + +%.squashfs.o: %.squashfs + $(LD) -s -r -b binary -m aarch64elf -T $(LIBTRANSISTOR_HOME)/fs.T -o $@ $< + +fs.squashfs: fs/* + mksquashfs $^ $@ -comp lz4 -nopad -noappend + +clean: + rm -f $(OBJ) $(TARGET).nro.so $(TARGET).nro + +.PHONY: clean all diff --git a/config.def.h b/config.def.h index e05b9c828b..6fb3c5de4d 100644 --- a/config.def.h +++ b/config.def.h @@ -324,6 +324,7 @@ static const uint32_t menu_title_color = 0xff64ff64; #else static bool default_block_config_read = false; +static bool automatically_add_content_to_playlist = false; #endif static bool default_game_specific_options = true; diff --git a/configuration.c b/configuration.c index 9f7d219424..87d8caddb0 100644 --- a/configuration.c +++ b/configuration.c @@ -130,6 +130,7 @@ enum video_driver_enum VIDEO_PSP1, VIDEO_VITA2D, VIDEO_CTR, + VIDEO_SWITCH, VIDEO_D3D9, VIDEO_VG, VIDEO_OMAP, @@ -190,6 +191,7 @@ enum input_driver_enum INPUT_PS3, INPUT_PSP, INPUT_CTR, + INPUT_SWITCH, INPUT_XENON360, INPUT_WII, INPUT_WIIU, @@ -212,6 +214,7 @@ enum joypad_driver_enum JOYPAD_XDK, JOYPAD_PSP, JOYPAD_CTR, + JOYPAD_SWITCH, JOYPAD_DINPUT, JOYPAD_UDEV, JOYPAD_LINUXRAW, @@ -288,6 +291,8 @@ static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_VITA2D; static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_PSP1; #elif defined(_3DS) static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_CTR; +#elif defined(SWITCH) +static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_SWITCH; #elif defined(HAVE_XVIDEO) static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_XVIDEO; #elif defined(HAVE_SDL) @@ -386,6 +391,8 @@ static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_PS3; static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_PSP; #elif defined(_3DS) static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_CTR; +#elif defined(SWITCH) +static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_SWITCH; #elif defined(GEKKO) static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_WII; #elif defined(WIIU) @@ -426,6 +433,8 @@ static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_XDK; static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_PSP; #elif defined(_3DS) static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_CTR; +#elif defined(SWITCH) +static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_SWITCH; #elif defined(HAVE_DINPUT) static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_DINPUT; #elif defined(HAVE_UDEV) @@ -684,6 +693,8 @@ const char *config_get_default_video(void) return "vita2d"; case VIDEO_CTR: return "ctr"; + case VIDEO_SWITCH: + return "switch"; case VIDEO_XVIDEO: return "xvideo"; case VIDEO_SDL: @@ -740,6 +751,8 @@ const char *config_get_default_input(void) #endif case INPUT_CTR: return "ctr"; + case INPUT_SWITCH: + return "switch"; case INPUT_SDL: return "sdl"; case INPUT_SDL2: @@ -808,6 +821,8 @@ const char *config_get_default_joypad(void) #endif case JOYPAD_CTR: return "ctr"; + case JOYPAD_SWITCH: + return "switch"; case JOYPAD_DINPUT: return "dinput"; case JOYPAD_UDEV: diff --git a/gfx/drivers/switch_gfx.c b/gfx/drivers/switch_gfx.c new file mode 100644 index 0000000000..9c059fc5d6 --- /dev/null +++ b/gfx/drivers/switch_gfx.c @@ -0,0 +1,271 @@ +#include +#include +#include + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#ifdef HAVE_MENU +#include "../../menu/menu_driver.h" +#endif + +#include "../font_driver.h" + +#include "../../configuration.h" +#include "../../command.h" +#include "../../driver.h" + +#include "../../retroarch.h" +#include "../../verbosity.h" + +#ifndef HAVE_THREADS +#include "../../tasks/tasks_internal.h" +#endif + +#include + +static void *switch_init(const video_info_t *video, const input_driver_t **input, void **input_data); +static bool switch_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); +static void switch_set_nonblock_state(void *data, bool toggle); +static bool switch_alive(void *data); +static bool switch_focus(void *data); +static bool switch_suppress_screensaver(void *data, bool enable); +static void switch_viewport_info(void *data, struct video_viewport *vp); +static bool read_viewport(void *data, uint8_t *buffer, bool is_idle); + +typedef struct { + surface_t surface; + unsigned width, height; + unsigned rotation; + bool vsync; + revent_h vsync_h; + struct video_viewport vp; +} switch_video_t; + +static uint32_t image[1280*720]; + +static void *switch_init(const video_info_t *video, + const input_driver_t **input, void **input_data) { + printf("loading switch gfx driver, width: %d, height: %d\n", video->width, video->height); + + switch_video_t *sw = malloc(sizeof(*sw)); + if(sw == NULL) { + return NULL; + } + + if(libtransistor_context.magic != LIBTRANSISTOR_CONTEXT_MAGIC) { + printf("running under CTU, skipping graphics init...\n"); + } else { + result_t r; + if((r = display_init()) != RESULT_OK) { + free(sw); + return NULL; + } + if((r = display_open_layer(&sw->surface)) != RESULT_OK) { + display_finalize(); + free(sw); + return NULL; + } + if((r = display_get_vsync_event(&sw->vsync_h)) != RESULT_OK) { + display_finalize(); + free(sw); + return NULL; + } + } + + sw->vp.x = 0; + sw->vp.y = 0; + sw->vp.width = 1280; + sw->vp.height = 720; + sw->vp.full_width = 1280; + sw->vp.full_height = 720; + video_driver_set_size(&sw->vp.width, &sw->vp.height); + + sw->vsync = video->vsync; + + *input = NULL; + *input_data = NULL; + + for(int x = 0; x < 1280; x++) { + for(int y = 0; y < 720; y++) { + image[(y*1280)+x] = 0xFF000000; + } + } + + return sw; +} + +static void switch_wait_vsync(switch_video_t *sw) { + uint32_t handle_idx; + svcWaitSynchronization(&handle_idx, &sw->vsync_h, 1, 33333333); + svcResetSignal(sw->vsync_h); +} + +static bool switch_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) { + switch_video_t *sw = data; + + int xsf = 1280/width; + int ysf = 720/height; + int sf = xsf; + if(ysf < sf) { sf = ysf; } + + uint16_t *frame_pixels = frame; + + int tgtw = width * sf; + int tgth = height * sf; + int centerx = (1280-tgtw)/2; + int centery = (720-tgth)/2; + + uint64_t begin = svcGetSystemTick(); + + for(int x = 0; x < width; x++) { + for(int y = 0; y < height; y++) { + uint32_t spixel = frame_pixels[(y*pitch/sizeof(uint16_t)) + x]; + uint8_t r = (spixel >> 11) & 31; r = (r * 256) / 32; + uint8_t g = (spixel >> 5) & 63; g = (g * 256) / 64; + uint8_t b = (spixel >> 0) & 31; b = (b * 256) / 32; + uint32_t dpixel = (r << 0) | (g << 8) | (b << 16) | (0xFF << 24); + for(int subx = 0; subx < xsf; subx++) { + for(int suby = 0; suby < ysf; suby++) { + image[(((y*sf)+suby+centery)*1280) + ((x*sf)+subx+centerx)] = dpixel; + } + } + } + } + + uint64_t done_copying = svcGetSystemTick(); + + //if(frame_count > 6000) { + // display_finalize(); + // exit(0); + //} + + if(libtransistor_context.magic != LIBTRANSISTOR_CONTEXT_MAGIC) { + printf("running under CTU; skipping frame\n"); + return true; + } + + if(msg != NULL && strlen(msg) > 0) { + printf("message: %s\n", msg); + } + + if(sw->vsync) { + switch_wait_vsync(sw); + } + + uint64_t post_vsync = svcGetSystemTick(); + + result_t r; + + uint32_t *out_buffer; + if((r = surface_dequeue_buffer(&sw->surface, &out_buffer)) != RESULT_OK) { + return false; + } + + uint64_t pre_swizzle = svcGetSystemTick(); + gfx_slow_swizzling_blit(out_buffer, image, 1280, 720, 0, 0); + uint64_t post_swizzle = svcGetSystemTick(); + if((r = surface_queue_buffer(&sw->surface)) != RESULT_OK) { + return false; + } + + uint64_t copy_ms = (done_copying - begin) / 19200; + uint64_t swizzle_ms = (post_swizzle - pre_swizzle) / 19200; + uint64_t vsync_ms = (post_vsync - done_copying) / 19200; + printf("frame %d benchmark: copy %ld ms, swizzle %ld ms, vsync %ld ms\n", frame_count, copy_ms, swizzle_ms, vsync_ms); + + return true; +} + +static void switch_set_nonblock_state(void *data, bool toggle) { + switch_video_t *sw = data; + sw->vsync = !toggle; +} + +static bool switch_alive(void *data) { + (void) data; + return true; +} + +static bool switch_focus(void *data) { + (void) data; + return true; +} + +static bool switch_suppress_screensaver(void *data, bool enable) { + (void) data; + (void) enable; + return false; +} + +static bool switch_has_windowed(void *data) { + (void) data; + return false; +} + +static void switch_free(void *data) { + switch_video_t *sw = data; + free(sw); + display_finalize(); +} + +static bool switch_set_shader(void *data, + enum rarch_shader_type type, const char *path) { + (void) data; + (void) type; + (void) path; + + return false; +} + +static void switch_set_rotation(void *data, unsigned rotation) { + switch_video_t *sw = data; + sw->rotation = rotation; +} + +static void switch_viewport_info(void *data, struct video_viewport *vp) { + switch_video_t *sw = data; + *vp = sw->vp; +} + +static bool switch_read_viewport(void *data, uint8_t *buffer, bool is_idle) { + (void) data; + (void) buffer; + + return true; +} + +static void switch_get_poke_interface(void *data, const video_poke_interface_t **iface) { + (void) data; + (void) iface; +} + +video_driver_t video_switch = { + switch_init, + switch_frame, + switch_set_nonblock_state, + switch_alive, + switch_focus, + switch_suppress_screensaver, + switch_has_windowed, + switch_set_shader, + switch_free, + "switch", + NULL, /* set_viewport */ + switch_set_rotation, + switch_viewport_info, + switch_read_viewport, + NULL, /* read_frame_raw */ +#ifdef HAVE_OVERLAY + NULL, /* overlay_interface */ +#endif + switch_get_poke_interface, +}; diff --git a/gfx/video_driver.c b/gfx/video_driver.c index da87988eb9..211cab34bd 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -274,6 +274,9 @@ static const video_driver_t *video_drivers[] = { #ifdef _3DS &video_ctr, #endif +#ifdef SWITCH + &video_switch, +#endif #ifdef HAVE_SDL &video_sdl, #endif diff --git a/gfx/video_driver.h b/gfx/video_driver.h index 6abae88e13..f1b19955b0 100644 --- a/gfx/video_driver.h +++ b/gfx/video_driver.h @@ -1339,6 +1339,7 @@ extern video_driver_t video_vulkan; extern video_driver_t video_psp1; extern video_driver_t video_vita2d; extern video_driver_t video_ctr; +extern video_driver_t video_switch; extern video_driver_t video_d3d; extern video_driver_t video_gx; extern video_driver_t video_wiiu; diff --git a/input/drivers/switch_input.c b/input/drivers/switch_input.c new file mode 100644 index 0000000000..81ddb33c69 --- /dev/null +++ b/input/drivers/switch_input.c @@ -0,0 +1,138 @@ +#include +#include + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#include "../input_driver.h" + +#define MAX_PADS 10 + +typedef struct switch_input { + const input_device_driver_t *joypad; + bool blocked; +} switch_input_t; + +static void switch_input_poll(void *data) { + switch_input_t *sw = (switch_input_t*) data; + + if(sw->joypad) { + sw->joypad->poll(); + } +} + +static int16_t switch_input_state(void *data, + rarch_joypad_info_t joypad_info, + const struct retro_keybind **binds, + unsigned port, unsigned device, + unsigned idx, unsigned id) { + switch_input_t *sw = (switch_input_t*) data; + + if (port > MAX_PADS-1) + return 0; + + switch (device) { + case RETRO_DEVICE_JOYPAD: + //return input_joypad_pressed(sw->joypad, + // joypad_info, port, binds[port], id); + if(sw->joypad) { + return sw->joypad->button(port, id); + } + case RETRO_DEVICE_ANALOG: + if(binds[port]) { + return input_joypad_analog(sw->joypad, + joypad_info, port, idx, id, binds[port]); + } + break; + } + + return 0; +} + +static void switch_input_free_input(void *data) { + switch_input_t *sw = (switch_input_t*) data; + + if (sw && sw->joypad) { + sw->joypad->destroy(); + } + + free(sw); +} + +static void* switch_input_init(const char *joypad_driver) { + switch_input_t *sw = (switch_input_t*) calloc(1, sizeof(*sw)); + if (!sw) + return NULL; + + sw->joypad = input_joypad_init_driver(joypad_driver, sw); + + return sw; +} + +static uint64_t switch_input_get_capabilities(void *data) { + (void) data; + + return (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG); +} + +static const input_device_driver_t *switch_input_get_joypad_driver(void *data) { + switch_input_t *sw = (switch_input_t*) data; + if(sw) { + return sw->joypad; + } + return NULL; +} + +static void switch_input_grab_mouse(void *data, bool state) { + (void)data; + (void)state; +} + +static bool switch_input_set_rumble(void *data, unsigned port, + enum retro_rumble_effect effect, uint16_t strength) { + (void)data; + (void)port; + (void)effect; + (void)strength; + + return false; +} + +static bool switch_input_keyboard_mapping_is_blocked(void *data) { + switch_input_t *sw = (switch_input_t*) data; + if (!sw) { + return false; + } + return sw->blocked; +} + +static void switch_input_keyboard_mapping_set_block(void *data, bool value) { + switch_input_t *sw = (switch_input_t*) data; + if(!sw) { + return; + } + sw->blocked = value; +} + +input_driver_t input_switch = { + switch_input_init, + switch_input_poll, + switch_input_state, + switch_input_free_input, + NULL, + NULL, + switch_input_get_capabilities, + "switch", + switch_input_grab_mouse, + NULL, + switch_input_set_rumble, + switch_input_get_joypad_driver, + NULL, + switch_input_keyboard_mapping_is_blocked, + switch_input_keyboard_mapping_set_block, +}; diff --git a/input/drivers_joypad/switch_joypad.c b/input/drivers_joypad/switch_joypad.c new file mode 100644 index 0000000000..33104227b6 --- /dev/null +++ b/input/drivers_joypad/switch_joypad.c @@ -0,0 +1,155 @@ +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#include "../input_driver.h" + +#include "../../tasks/tasks_internal.h" + +#include "../../retroarch.h" +#include "../../command.h" +#include "string.h" + +#include + +#ifndef MAX_PADS +#define MAX_PADS 10 +#endif + +static uint16_t pad_state[MAX_PADS]; +static int16_t analog_state[MAX_PADS][2][2]; +extern uint64_t lifecycle_state; + +static const char *switch_joypad_name(unsigned pad) { + return "Switch Controller"; +} + +static void switch_joypad_autodetect_add(unsigned autoconf_pad) { + if(!input_autoconfigure_connect( + switch_joypad_name(autoconf_pad), // name + NULL, // display name + switch_joypad.ident, // driver + autoconf_pad, // idx + 0, // vid + 0)) { // pid + input_config_set_device_name(autoconf_pad, switch_joypad_name(autoconf_pad)); + } +} + +static bool switch_joypad_init(void *data) { + hid_init(); + + switch_joypad_autodetect_add(0); + switch_joypad_autodetect_add(1); + printf("init switch joypad\n"); + + return true; +} + +static bool switch_joypad_button(unsigned port_num, uint16_t key) { + if(port_num >= MAX_PADS) { + return false; + } + + //printf("button(%d, %d)\n", port_num, key); + + return (pad_state[port_num] & (1 << key)); +} + +static void switch_joypad_get_buttons(unsigned port_num, retro_bits_t *state) { + printf("get buttons %d\n", port_num); + if(port_num < MAX_PADS) { + BITS_COPY16_PTR(state, pad_state[port_num]); + } else { + BIT256_CLEAR_ALL_PTR(state); + } +} + +static int16_t switch_joypad_axis(unsigned port_num, uint32_t joyaxis) { + int val = 0; + int axis = -1; + bool is_neg = false; + bool is_pos = false; + + if(joyaxis == AXIS_NONE || port_num >= MAX_PADS) { + } + + if(AXIS_NEG_GET(joyaxis) < 4) { + axis = AXIS_NEG_GET(joyaxis); + is_neg = true; + } else if(AXIS_POS_GET(joyaxis) < 4) { + axis = AXIS_POS_GET(joyaxis); + is_pos = true; + } + + switch(axis) { + case 0: + val = analog_state[port_num][0][0]; + break; + case 1: + val = analog_state[port_num][0][1]; + break; + case 2: + val = analog_state[port_num][1][0]; + break; + case 3: + val = analog_state[port_num][1][1]; + break; + } + + if(is_neg && val > 0) { + val = 0; + } else if(is_pos && val < 0) { + val = 0; + } + + return val; +} + +static bool switch_joypad_query_pad(unsigned pad) { + printf("query %d\n", pad); + return pad < MAX_PADS && pad_state[pad]; +} + +static void switch_joypad_destroy(void) { + hid_finalize(); +} + +static void switch_joypad_poll(void) { + hid_controller_t *controllers = hid_get_shared_memory()->controllers; + hid_controller_t *cont = &controllers[0]; + hid_controller_state_entry_t ent = cont->main.entries[cont->main.latest_idx]; + pad_state[0] = 0; + pad_state[0]|= (ent.button_state & 0x1000) ? (1 << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0; + pad_state[0]|= (ent.button_state & 0x8000) ? (1 << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0; + pad_state[0]|= (ent.button_state & 0x4000) ? (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0; + pad_state[0]|= (ent.button_state & 0x2000) ? (1 << RETRO_DEVICE_ID_JOYPAD_UP) : 0; + pad_state[0]|= (ent.button_state & 0x0400) ? (1 << RETRO_DEVICE_ID_JOYPAD_START) : 0; + pad_state[0]|= (ent.button_state & 0x0800) ? (1 << RETRO_DEVICE_ID_JOYPAD_SELECT) : 0; + pad_state[0]|= (ent.button_state & 0x0004) ? (1 << RETRO_DEVICE_ID_JOYPAD_X) : 0; + pad_state[0]|= (ent.button_state & 0x0008) ? (1 << RETRO_DEVICE_ID_JOYPAD_Y) : 0; + pad_state[0]|= (ent.button_state & 0x0002) ? (1 << RETRO_DEVICE_ID_JOYPAD_B) : 0; + pad_state[0]|= (ent.button_state & 0x0001) ? (1 << RETRO_DEVICE_ID_JOYPAD_A) : 0; + pad_state[0]|= (ent.button_state & 0x0080) ? (1 << RETRO_DEVICE_ID_JOYPAD_R) : 0; + pad_state[0]|= (ent.button_state & 0x0040) ? (1 << RETRO_DEVICE_ID_JOYPAD_L) : 0; + pad_state[0]|= (ent.button_state & 0x0200) ? (1 << RETRO_DEVICE_ID_JOYPAD_R2) : 0; + pad_state[0]|= (ent.button_state & 0x0100) ? (1 << RETRO_DEVICE_ID_JOYPAD_L2) : 0; + + analog_state[0][RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_X] = ent.left_stick_x / 0x20000; + analog_state[0][RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_Y] = ent.left_stick_y / 0x20000; + analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_X] = ent.left_stick_x / 0x20000; + analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_Y] = ent.left_stick_y / 0x20000; +} + +input_device_driver_t switch_joypad = { + switch_joypad_init, + switch_joypad_query_pad, + switch_joypad_destroy, + switch_joypad_button, + switch_joypad_get_buttons, + switch_joypad_axis, + switch_joypad_poll, + NULL, // set_rumble + switch_joypad_name, + "switch" +}; diff --git a/input/input_driver.c b/input/input_driver.c index 3d5ee6ca73..730e0f3df1 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -71,6 +71,9 @@ static const input_driver_t *input_drivers[] = { #if defined(_3DS) &input_ctr, #endif +#if defined(SWITCH) + &input_switch, +#endif #if defined(HAVE_SDL) || defined(HAVE_SDL2) &input_sdl, #endif @@ -143,6 +146,9 @@ static input_device_driver_t *joypad_drivers[] = { #ifdef _3DS &ctr_joypad, #endif +#ifdef SWITCH + &switch_joypad, +#endif #ifdef HAVE_DINPUT &dinput_joypad, #endif diff --git a/input/input_driver.h b/input/input_driver.h index beed89459a..96a02c9831 100644 --- a/input/input_driver.h +++ b/input/input_driver.h @@ -790,6 +790,7 @@ extern input_device_driver_t sdl_joypad; extern input_device_driver_t ps3_joypad; extern input_device_driver_t psp_joypad; extern input_device_driver_t ctr_joypad; +extern input_device_driver_t switch_joypad; extern input_device_driver_t xdk_joypad; extern input_device_driver_t gx_joypad; extern input_device_driver_t wiiu_joypad; @@ -807,6 +808,7 @@ extern input_driver_t input_x; extern input_driver_t input_ps3; extern input_driver_t input_psp; extern input_driver_t input_ctr; +extern input_driver_t input_switch; extern input_driver_t input_xenon360; extern input_driver_t input_gx; extern input_driver_t input_wiiu; diff --git a/libretro-common/features/features_cpu.c b/libretro-common/features/features_cpu.c index f292b1ac11..0249cfe4e1 100644 --- a/libretro-common/features/features_cpu.c +++ b/libretro-common/features/features_cpu.c @@ -79,6 +79,11 @@ #include #endif +#ifdef SWITCH +#include +#include +#endif + #if defined(_3DS) #include <3ds/svc.h> #include <3ds/os.h> @@ -230,6 +235,8 @@ retro_time_t cpu_features_get_time_usec(void) return sceKernelGetProcessTimeWide(); #elif defined(WIIU) return ticks_to_us(OSGetSystemTime()); +#elif defined(SWITCH) + return (svcGetSystemTick() * 10) / 192; #else #error "Your platform does not have a timer function implemented in cpu_features_get_time_usec(). Cannot continue." #endif diff --git a/libretro-common/include/memmap.h b/libretro-common/include/memmap.h index dc065e178c..8d939c4351 100644 --- a/libretro-common/include/memmap.h +++ b/libretro-common/include/memmap.h @@ -26,7 +26,7 @@ #include #include -#if defined(__CELLOS_LV2__) || defined(PSP) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) +#if defined(__CELLOS_LV2__) || defined(PSP) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH) /* No mman available */ #elif defined(_WIN32) && !defined(_XBOX) #include