Skip to content

Switch 3.2.14 Port #99

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: switch-sdl-3.2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 55 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,13 @@ endif()
# for the time being. This default will change to ON once this becomes
# commonly supported in browsers or the Emscripten team makes a single
# binary work everywhere.
if (UNIX_OR_MAC_SYS AND NOT EMSCRIPTEN)
if ((UNIX_OR_MAC_SYS OR NINTENDO_SWITCH) AND NOT EMSCRIPTEN)
set(SDL_PTHREADS_DEFAULT ON)
else()
set(SDL_PTHREADS_DEFAULT OFF)
endif()

if(UNIX_SYS OR ANDROID)
if((UNIX_SYS OR NINTENDO_SWITCH) OR ANDROID)
set(SDL_CLOCK_GETTIME_DEFAULT ON)
else()
set(SDL_CLOCK_GETTIME_DEFAULT OFF)
Expand Down Expand Up @@ -219,7 +219,7 @@ if(EMSCRIPTEN)
set(SDL_SHARED_AVAILABLE OFF)
endif()

if(VITA OR PSP OR PS2 OR N3DS OR RISCOS)
if(VITA OR PSP OR PS2 OR N3DS OR RISCOS OR NINTENDO_SWITCH)
set(SDL_SHARED_AVAILABLE OFF)
endif()

Expand Down Expand Up @@ -2924,6 +2924,58 @@ elseif(N3DS)
set(HAVE_SDL_LOCALE TRUE)

sdl_glob_sources("${SDL3_SOURCE_DIR}/src/io/n3ds/*.c")
elseif(NINTENDO_SWITCH)
sdl_link_dependency(nx LIBS nx)

if(SDL_VIDEO)
set(SDL_VIDEO_DRIVER_SWITCH 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/switch/*.c")
set(HAVE_SDL_VIDEO TRUE)

CheckEGL()
if(HAVE_OPENGL_EGL)
sdl_link_dependency(opengl LIBS EGL glapi drm_nouveau)
endif()

CheckOpenGLES()
CheckOpenGL()

sdl_compile_options(PRIVATE -DSDL_VIDEO_STATIC_ANGLE)
endif()

if(SDL_AUDIO)
set(SDL_AUDIO_DRIVER_SWITCH 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/switch/*.c")
set(HAVE_SDL_AUDIO TRUE)
endif()

set(SDL_FILESYSTEM_SWITCH 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/filesystem/switch/*.c")
set(HAVE_SDL_FILESYSTEM TRUE)

if(SDL_POWER)
set(SDL_POWER_SWITCH 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/power/switch/*.c")
set(HAVE_SDL_POWER TRUE)
endif()

if(SDL_JOYSTICK)
set(SDL_JOYSTICK_SWITCH 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/switch/*.c")
set(HAVE_SDL_JOYSTICK TRUE)
endif()

CheckPTHREAD()

if(SDL_CLOCK_GETTIME)
set(HAVE_CLOCK_GETTIME 1)
endif()

set(SDL_TIMER_SWITCH 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/timer/switch/*.c")
set(HAVE_SDL_TIMERS TRUE)

set(SDL_STATIC_PIC TRUE)
endif()

sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/SDL_dialog.c)
Expand Down
2 changes: 2 additions & 0 deletions cmake/sdlplatform.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ function(SDL_DetectCMakePlatform)
set(sdl_cmake_platform )
if(WIN32)
set(sdl_cmake_platform Windows)
elseif(NINTENDO_SWITCH)
set(sdl_cmake_platform NintendoSwitch)
elseif(PSP)
set(sdl_cmake_platform psp)
elseif(APPLE)
Expand Down
4 changes: 4 additions & 0 deletions include/SDL3/SDL_platform_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -473,4 +473,8 @@
#define SDL_PLATFORM_3DS 1
#endif

#if defined(__SWITCH__) && __SWITCH__
#define SDL_PLATFORM_SWITCH 1
#endif

#endif /* SDL_platform_defines_h_ */
6 changes: 6 additions & 0 deletions include/build_config/SDL_build_config.h.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@
#cmakedefine SDL_AUDIO_DRIVER_PSP 1
#cmakedefine SDL_AUDIO_DRIVER_PS2 1
#cmakedefine SDL_AUDIO_DRIVER_N3DS 1
#cmakedefine SDL_AUDIO_DRIVER_SWITCH 1
#cmakedefine SDL_AUDIO_DRIVER_QNX 1

/* Enable various input drivers */
Expand Down Expand Up @@ -299,6 +300,7 @@
#cmakedefine SDL_JOYSTICK_VITA 1
#cmakedefine SDL_JOYSTICK_WGI 1
#cmakedefine SDL_JOYSTICK_XINPUT 1
#cmakedefine SDL_JOYSTICK_SWITCH 1
#cmakedefine SDL_HAPTIC_DUMMY 1
#cmakedefine SDL_HAPTIC_LINUX 1
#cmakedefine SDL_HAPTIC_IOKIT 1
Expand Down Expand Up @@ -353,6 +355,7 @@
#cmakedefine SDL_TIMER_PSP 1
#cmakedefine SDL_TIMER_PS2 1
#cmakedefine SDL_TIMER_N3DS 1
#cmakedefine SDL_TIMER_SWITCH 1

/* Enable various video drivers */
#cmakedefine SDL_VIDEO_DRIVER_ANDROID 1
Expand Down Expand Up @@ -402,6 +405,7 @@
#cmakedefine SDL_VIDEO_DRIVER_X11_XSHAPE 1
#cmakedefine SDL_VIDEO_DRIVER_X11_XSYNC 1
#cmakedefine SDL_VIDEO_DRIVER_QNX 1
#cmakedefine SDL_VIDEO_DRIVER_SWITCH 1

#cmakedefine SDL_VIDEO_RENDER_D3D 1
#cmakedefine SDL_VIDEO_RENDER_D3D11 1
Expand Down Expand Up @@ -448,6 +452,7 @@
#cmakedefine SDL_POWER_VITA 1
#cmakedefine SDL_POWER_PSP 1
#cmakedefine SDL_POWER_N3DS 1
#cmakedefine SDL_POWER_SWITCH 1

/* Enable system filesystem support */
#cmakedefine SDL_FILESYSTEM_ANDROID 1
Expand All @@ -462,6 +467,7 @@
#cmakedefine SDL_FILESYSTEM_PSP 1
#cmakedefine SDL_FILESYSTEM_PS2 1
#cmakedefine SDL_FILESYSTEM_N3DS 1
#cmakedefine SDL_FILESYSTEM_SWITCH 1

/* Enable system storage support */
#cmakedefine SDL_STORAGE_STEAM @SDL_STORAGE_STEAM@
Expand Down
3 changes: 3 additions & 0 deletions src/audio/SDL_audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ static const AudioBootStrap *const bootstrap[] = {
#ifdef SDL_AUDIO_DRIVER_N3DS
&N3DSAUDIO_bootstrap,
#endif
#ifdef SDL_AUDIO_DRIVER_SWITCH
&SWITCHAUDIO_bootstrap,
#endif
#ifdef SDL_AUDIO_DRIVER_EMSCRIPTEN
&EMSCRIPTENAUDIO_bootstrap,
#endif
Expand Down
1 change: 1 addition & 0 deletions src/audio/SDL_sysaudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ extern AudioBootStrap PS2AUDIO_bootstrap;
extern AudioBootStrap PSPAUDIO_bootstrap;
extern AudioBootStrap VITAAUD_bootstrap;
extern AudioBootStrap N3DSAUDIO_bootstrap;
extern AudioBootStrap SWITCHAUDIO_bootstrap;
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
extern AudioBootStrap QSAAUDIO_bootstrap;

Expand Down
223 changes: 223 additions & 0 deletions src/audio/switch/SDL_switchaudio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <[email protected]>

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"

#if SDL_AUDIO_DRIVER_SWITCH

#include <malloc.h>
#include <string.h>

#include "SDL_switchaudio.h"

// clang-format off
static const AudioRendererConfig arConfig = {
.output_rate = AudioRendererOutputRate_48kHz,
.num_voices = 24,
.num_effects = 0,
.num_sinks = 1,
.num_mix_objs = 1,
.num_mix_buffers = 2,
};
// clang-format on

static bool SWITCHAUDIO_OpenDevice(SDL_AudioDevice *device)
{
static const u8 sink_channels[] = { 0, 1 };
bool supported_format = false;
SDL_AudioFormat test_format;
Result res;
u32 size;
int mpid;
const SDL_AudioFormat *closefmts;

device->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_zerop(device->hidden);

res = audrenInitialize(&arConfig);
if (R_FAILED(res)) {
return SDL_SetError("audrenInitialize failed (0x%x)", res);
}
device->hidden->audr_device = true;

res = audrvCreate(&device->hidden->driver, &arConfig, 2);
if (R_FAILED(res)) {
return SDL_SetError("audrvCreate failed (0x%x)", res);
}
device->hidden->audr_driver = true;

closefmts = SDL_ClosestAudioFormats(device->spec.format);
while ((test_format = *(closefmts++)) != 0) {
if (test_format == SDL_AUDIO_S16) {
supported_format = true;
break;
}
}

if (!supported_format) {
return SDL_SetError("Unsupported audio format");
}

device->spec.format = test_format;

SDL_UpdatedAudioDeviceFormat(device);

if (device->buffer_size >= SDL_MAX_UINT32 / 2) {
return SDL_SetError("Mixing buffer is too large.");
}

size = (u32)((device->buffer_size * 2) + 0xfff) & ~0xfff;
device->hidden->pool = memalign(0x1000, size);
for (int i = 0; i < 2; i++) {
device->hidden->buffer[i].data_raw = device->hidden->pool;
device->hidden->buffer[i].size = device->buffer_size * 2;
device->hidden->buffer[i].start_sample_offset = i * device->sample_frames;
device->hidden->buffer[i].end_sample_offset = device->hidden->buffer[i].start_sample_offset + device->sample_frames;
device->hidden->buffer_tmp = SDL_malloc(device->buffer_size);
}

mpid = audrvMemPoolAdd(&device->hidden->driver, device->hidden->pool, size);
audrvMemPoolAttach(&device->hidden->driver, mpid);

audrvDeviceSinkAdd(&device->hidden->driver, AUDREN_DEFAULT_DEVICE_NAME, 2, sink_channels);

res = audrenStartAudioRenderer();
if (R_FAILED(res)) {
return SDL_SetError("audrenStartAudioRenderer failed (0x%x)", res);
}

audrvVoiceInit(&device->hidden->driver, 0, device->spec.channels, PcmFormat_Int16, device->spec.freq);
audrvVoiceSetDestinationMix(&device->hidden->driver, 0, AUDREN_FINAL_MIX_ID);
if (device->spec.channels == 1) {
audrvVoiceSetMixFactor(&device->hidden->driver, 0, 1.0f, 0, 0);
audrvVoiceSetMixFactor(&device->hidden->driver, 0, 1.0f, 0, 1);
} else {
audrvVoiceSetMixFactor(&device->hidden->driver, 0, 1.0f, 0, 0);
audrvVoiceSetMixFactor(&device->hidden->driver, 0, 0.0f, 0, 1);
audrvVoiceSetMixFactor(&device->hidden->driver, 0, 0.0f, 1, 0);
audrvVoiceSetMixFactor(&device->hidden->driver, 0, 1.0f, 1, 1);
}

audrvVoiceStart(&device->hidden->driver, 0);

return true;
}

static bool SWITCHAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
{
int current = -1;
for (int i = 0; i < 2; i++) {
if (device->hidden->buffer[i].state == AudioDriverWaveBufState_Free || device->hidden->buffer[i].state == AudioDriverWaveBufState_Done) {
current = i;
break;
}
}

/* paranoia */
SDL_assert(buffer == device->hidden->buffer_tmp);
SDL_assert(buflen == device->buffer_size);

if (current >= 0) {
Uint8 *ptr = (Uint8 *)(device->hidden->pool + (current * device->buffer_size));
memcpy(ptr, device->hidden->buffer_tmp, device->buffer_size);
armDCacheFlush(ptr, device->buffer_size);
audrvVoiceAddWaveBuf(&device->hidden->driver, 0, &device->hidden->buffer[current]);
} else if (!audrvVoiceIsPlaying(&device->hidden->driver, 0)) {
audrvVoiceStart(&device->hidden->driver, 0);
}

audrvUpdate(&device->hidden->driver);

if (current >= 0) {
while (device->hidden->buffer[current].state != AudioDriverWaveBufState_Playing) {
audrvUpdate(&device->hidden->driver);
audrenWaitFrame();
}
} else {
current = -1;
for (int i = 0; i < 2; i++) {
if (device->hidden->buffer[i].state == AudioDriverWaveBufState_Playing) {
current = i;
break;
}
}
while (device->hidden->buffer[current].state == AudioDriverWaveBufState_Playing) {
audrvUpdate(&device->hidden->driver);
audrenWaitFrame();
}
}

return true;
}

static bool SWITCHAUDIO_WaitDevice(SDL_AudioDevice *device)
{
return true;
}

static Uint8 *SWITCHAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
return device->hidden->buffer_tmp;
}

static void SWITCHAUDIO_CloseDevice(SDL_AudioDevice *device)
{
if (device->hidden->audr_driver) {
audrvClose(&device->hidden->driver);
}

if (device->hidden->audr_device) {
audrenExit();
}

if (device->hidden->buffer_tmp) {
free(device->hidden->buffer_tmp);
}

SDL_free(device->hidden);
}

static bool SWITCHAUDIO_Init(SDL_AudioDriverImpl *impl)
{
impl->OpenDevice = SWITCHAUDIO_OpenDevice;
impl->PlayDevice = SWITCHAUDIO_PlayDevice;
impl->WaitDevice = SWITCHAUDIO_WaitDevice;
impl->GetDeviceBuf = SWITCHAUDIO_GetDeviceBuf;
impl->CloseDevice = SWITCHAUDIO_CloseDevice;

impl->OnlyHasDefaultPlaybackDevice = true;

return 1;
}

// clang-format off
AudioBootStrap SWITCHAUDIO_bootstrap = {
.name = "switch",
.desc = "Nintendo Switch audio driver",
.init = SWITCHAUDIO_Init,
.demand_only = false,
.is_preferred = true,
};
// clang-format on

#endif /* SDL_AUDIO_DRIVER_SWITCH */
Loading