From 005829b775c13396de53a6de2bae580a6e49e1d6 Mon Sep 17 00:00:00 2001 From: Cpasjuste Date: Sat, 10 Mar 2018 22:02:38 +0100 Subject: [PATCH] SWITCH: first commit, missing audio, input... (#1) * SWITCH: first commit, missing audio, input... --- CMakeLists.switch | 78 +++++++++++++ configure.ac | 1 + src/thread/switch/SDL_syscond.c | 140 ++++++++++++++++++++++ src/thread/switch/SDL_sysmutex.c | 122 ++++++++++++++++++++ src/thread/switch/SDL_sysmutex_c.h | 22 ++++ src/thread/switch/SDL_syssem.c | 172 ++++++++++++++++++++++++++++ src/thread/switch/SDL_systhread.c | 87 ++++++++++++++ src/thread/switch/SDL_systhread_c.h | 4 +- src/thread/switch/SDL_systls.c | 34 ++++++ src/thread/switch/dummy.c | 0 src/timer/switch/SDL_systimer.c | 78 +++++++++++++ src/timer/switch/dummy.c | 0 src/video/SDL_sysvideo.h | 1 + src/video/SDL_video.c | 3 + src/video/switch/SDL_switchvideo.c | 168 +++++++++++++++++++++++++++ src/video/switch/dummy.c | 0 test/testswitch.c | 69 +++++++++++ 17 files changed, 977 insertions(+), 2 deletions(-) create mode 100644 CMakeLists.switch create mode 100644 src/thread/switch/SDL_syscond.c create mode 100644 src/thread/switch/SDL_sysmutex.c create mode 100644 src/thread/switch/SDL_sysmutex_c.h create mode 100644 src/thread/switch/SDL_syssem.c create mode 100644 src/thread/switch/SDL_systhread.c create mode 100644 src/thread/switch/SDL_systls.c delete mode 100644 src/thread/switch/dummy.c create mode 100644 src/timer/switch/SDL_systimer.c delete mode 100644 src/timer/switch/dummy.c create mode 100644 src/video/switch/SDL_switchvideo.c delete mode 100644 src/video/switch/dummy.c create mode 100644 test/testswitch.c diff --git a/CMakeLists.switch b/CMakeLists.switch new file mode 100644 index 000000000..a0fed8f9d --- /dev/null +++ b/CMakeLists.switch @@ -0,0 +1,78 @@ +cmake_minimum_required(VERSION 3.0) +#set(CMAKE_VERBOSE_MAKEFILE ON) + +set(CMAKE_SYSTEM_NAME "Generic") + +set(DEVKITPRO $ENV{DEVKITPRO}) +set(CMAKE_SYSTEM_PROCESSOR "armv8-a") +set(CMAKE_C_COMPILER "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc") +set(CMAKE_CXX_COMPILER "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-g++") +set(CMAKE_ASM_COMPILER "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-as") +set(CMAKE_AR "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc-ar" CACHE STRING "") +set(CMAKE_RANLIB "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc-ranlib" CACHE STRING "") +set(CMAKE_C_FLAGS "-O2 -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIC -ftls-model=local-exec -I${DEVKITPRO}/libnx/include -I${DEVKITPRO}/portlibs/switch/include" CACHE STRING "C flags") +set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fpermissive -fno-rtti -fno-exceptions -std=gnu++11" CACHE STRING "C++ flags") +set(CMAKE_FIND_ROOT_PATH ${DEVKITPRO} ${DEVKITPRO}/devkitA64 ${DEVKITPRO}/libnx ${DEVKITPRO}/portlibs/switch) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) +set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Shared libs not available") + +project(SDL2) + +set(SRC_DIRS + src + src/atomic + src/audio + #src/audio/switch + src/audio/dummy + src/cpuinfo + src/events + src/file + src/filesystem/dummy + src/haptic + src/haptic/dummy + src/joystick + #src/joystick/switch + src/joystick/dummy + src/libm + src/power + src/render + src/render/software + src/stdlib + src/thread + src/thread/switch + src/timer + src/timer/switch + src/video + src/video/yuv2rgb + src/video/switch + ) + +set(SRC_FILES ) +foreach (DIR ${SRC_DIRS}) + file(GLOB FILES ${DIR}/*.c*) + list(APPEND SRC_FILES ${FILES}) +endforeach (DIR) + +# SDL2 library +add_library(${PROJECT_NAME} STATIC ${SRC_FILES}) +target_include_directories(${PROJECT_NAME} PUBLIC ${SRC_DIRS} include) +target_compile_options(${PROJECT_NAME} PUBLIC -O3 -DSWITCH) + +# SDL2 test +add_executable(${PROJECT_NAME}.elf test/testswitch.c) +target_include_directories(${PROJECT_NAME}.elf PRIVATE include) +#target_include_directories(${PROJECT_NAME}.elf PRIVATE ${DEVKITPRO}/portlibs/switch/include) +target_compile_options(${PROJECT_NAME}.elf PRIVATE -O3 -DSWITCH) +target_link_libraries(${PROJECT_NAME}.elf + ${PROJECT_NAME} + #${DEVKITPRO}/portlibs/switch/lib/libSDL2.a + ${DEVKITPRO}/libnx/lib/libnx.a + m + ) +set_target_properties(${PROJECT_NAME}.elf PROPERTIES LINK_FLAGS "-specs=${DEVKITPRO}/libnx/switch.specs") +add_custom_target(${PROJECT_NAME}.nro + DEPENDS ${PROJECT_NAME}.elf + COMMAND elf2nro ${PROJECT_NAME}.elf ${PROJECT_NAME}.nro) diff --git a/configure.ac b/configure.ac index cd5704585..ed7be4f05 100644 --- a/configure.ac +++ b/configure.ac @@ -4233,6 +4233,7 @@ AS_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau aarch64-none-elf*) ARCH=switch EXTRA_CFLAGS="$EXTRA_CFLAGS -isystem${DEVKITPRO}/libnx/include -I${DEVKITPRO}/portlibs/switch/include -D__SWITCH__=1" + EXTRA_CFLAGS="$EXTRA_CFLAGS -g -O2 -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIC -ftls-model=local-exec" CheckDeclarationAfterStatement CheckDiskAudio CheckDummyAudio diff --git a/src/thread/switch/SDL_syscond.c b/src/thread/switch/SDL_syscond.c new file mode 100644 index 000000000..435c99b8f --- /dev/null +++ b/src/thread/switch/SDL_syscond.c @@ -0,0 +1,140 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 Sam Lantinga + + 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 +#include "../../SDL_internal.h" + +#if SDL_THREAD_SWITCH + +/* An implementation of condition variables using semaphores and mutexes */ +/* + This implementation borrows heavily from the BeOS condition variable + implementation, written by Christopher Tate and Owen Smith. Thanks! + */ + +#include "SDL_thread.h" + +struct SDL_cond +{ + Mutex mutex; + CondVar var; +}; + +/* Create a condition variable */ +SDL_cond * +SDL_CreateCond(void) +{ + SDL_cond *cond; + + cond = (SDL_cond *) SDL_malloc(sizeof(SDL_cond)); + if (cond) { + mutexInit(&cond->mutex); + condvarInit(&cond->var, &cond->mutex); + } + else { + SDL_OutOfMemory(); + } + return (cond); +} + +/* Destroy a condition variable */ +void +SDL_DestroyCond(SDL_cond *cond) +{ + if (cond) { + SDL_free(cond); + } +} + +/* Restart one of the threads that are waiting on the condition variable */ +int +SDL_CondSignal(SDL_cond *cond) +{ + if (!cond) { + return SDL_SetError("Passed a NULL condition variable"); + } + + condvarWakeOne(&cond->var); + + return 0; +} + +/* Restart all threads that are waiting on the condition variable */ +int +SDL_CondBroadcast(SDL_cond *cond) +{ + if (!cond) { + return SDL_SetError("Passed a NULL condition variable"); + } + + condvarWakeAll(&cond->var); + + return 0; +} + +/* Wait on the condition variable for at most 'ms' milliseconds. + The mutex must be locked before entering this function! + The mutex is unlocked during the wait, and locked again after the wait. + +Typical use: + +Thread A: + SDL_LockMutex(lock); + while ( ! condition ) { + SDL_CondWait(cond, lock); + } + SDL_UnlockMutex(lock); + +Thread B: + SDL_LockMutex(lock); + ... + condition = true; + ... + SDL_CondSignal(cond); + SDL_UnlockMutex(lock); + */ +int +SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms) +{ + if (!cond) { + return SDL_SetError("Passed a NULL condition variable"); + } + + /* Unlock the mutex, as is required by condition variable semantics */ + SDL_UnlockMutex(mutex); + + condvarWaitTimeout(&cond->var, ms * 1000000); + + /* Lock the mutex, as is required by condition variable semantics */ + SDL_LockMutex(mutex); + + return 0; +} + +/* Wait on the condition variable forever */ +int +SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex) +{ + return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT); +} + +#endif /* SDL_THREAD_SWITCH */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/thread/switch/SDL_sysmutex.c b/src/thread/switch/SDL_sysmutex.c new file mode 100644 index 000000000..6f2b07aee --- /dev/null +++ b/src/thread/switch/SDL_sysmutex.c @@ -0,0 +1,122 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 Sam Lantinga + + 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_THREAD_SWITCH + +/* An implementation of mutexes using semaphores */ + +#include "SDL_thread.h" +#include "SDL_systhread_c.h" + +struct SDL_mutex +{ + int recursive; + Uint32 owner; + Mutex mutex; +}; + +/* Create a mutex */ +SDL_mutex * +SDL_CreateMutex(void) +{ + SDL_mutex *mutex; + + mutex = (SDL_mutex *) SDL_malloc(sizeof(*mutex)); + if (mutex) { + mutexInit(&mutex->mutex); + mutex->recursive = 0; + mutex->owner = 0; + } + else { + SDL_OutOfMemory(); + } + return mutex; +} + +/* Free the mutex */ +void +SDL_DestroyMutex(SDL_mutex *mutex) +{ + if (mutex) { + SDL_free(mutex); + } +} + +/* Lock the semaphore */ +int +SDL_mutexP(SDL_mutex *mutex) +{ + Uint32 this_thread; + + if (mutex == NULL) { + SDL_SetError("Passed a NULL mutex"); + return -1; + } + + this_thread = (Uint32) SDL_ThreadID(); + if (mutex->owner == this_thread) { + ++mutex->recursive; + } + else { + /* The order of operations is important. + We set the locking thread id after we obtain the lock + so unlocks from other threads will fail. + */ + mutexLock(&mutex->mutex); + mutex->owner = this_thread; + mutex->recursive = 0; + } + + return 0; +} + +/* Unlock the mutex */ +int +SDL_mutexV(SDL_mutex *mutex) +{ + if (mutex == NULL) { + SDL_SetError("Passed a NULL mutex"); + return -1; + } + + /* If we don't own the mutex, we can't unlock it */ + if (SDL_ThreadID() != mutex->owner) { + SDL_SetError("mutex not owned by this thread"); + return -1; + } + + if (mutex->recursive) { + --mutex->recursive; + } + else { + /* The order of operations is important. + First reset the owner so another thread doesn't lock + the mutex and set the ownership before we reset it, + then release the lock semaphore. + */ + mutex->owner = 0; + mutexUnlock(&mutex->mutex); + } + return 0; +} + +#endif /* SDL_THREAD_SWITCH */ diff --git a/src/thread/switch/SDL_sysmutex_c.h b/src/thread/switch/SDL_sysmutex_c.h new file mode 100644 index 000000000..307537fc9 --- /dev/null +++ b/src/thread/switch/SDL_sysmutex_c.h @@ -0,0 +1,22 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 Sam Lantinga + + 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" diff --git a/src/thread/switch/SDL_syssem.c b/src/thread/switch/SDL_syssem.c new file mode 100644 index 000000000..9863d3637 --- /dev/null +++ b/src/thread/switch/SDL_syssem.c @@ -0,0 +1,172 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 Sam Lantinga + + 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_THREAD_SWITCH + +/* Semaphore functions for the VITA. */ + +#include + +#include "SDL_error.h" +#include "SDL_thread.h" +#include "SDL_timer.h" + +struct SDL_semaphore +{ + Uint32 count; + Uint32 waiters_count; + SDL_mutex *count_lock; + SDL_cond *count_nonzero; +}; + +/* Create a semaphore */ +SDL_sem *SDL_CreateSemaphore(Uint32 initial_value) +{ + SDL_sem *sem; + + sem = (SDL_sem *) SDL_malloc(sizeof(*sem)); + if (!sem) { + SDL_OutOfMemory(); + return NULL; + } + sem->count = initial_value; + sem->waiters_count = 0; + + sem->count_lock = SDL_CreateMutex(); + sem->count_nonzero = SDL_CreateCond(); + if (!sem->count_lock || !sem->count_nonzero) { + SDL_DestroySemaphore(sem); + return NULL; + } + + return sem; +} + +/* Free the semaphore */ +void SDL_DestroySemaphore(SDL_sem *sem) +{ + if (sem) { + sem->count = 0xFFFFFFFF; + while (sem->waiters_count > 0) { + SDL_CondSignal(sem->count_nonzero); + SDL_Delay(10); + } + SDL_DestroyCond(sem->count_nonzero); + if (sem->count_lock) { + SDL_mutexP(sem->count_lock); + SDL_mutexV(sem->count_lock); + SDL_DestroyMutex(sem->count_lock); + } + SDL_free(sem); + } +} + +/* TODO: This routine is a bit overloaded. + * If the timeout is 0 then just poll the semaphore; if it's SDL_MUTEX_MAXWAIT, pass + * NULL to sceKernelWaitSema() so that it waits indefinitely; and if the timeout + * is specified, convert it to microseconds. */ +int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout) +{ + int retval; + + if (!sem) { + SDL_SetError("Passed a NULL semaphore"); + return -1; + } + + /* A timeout of 0 is an easy case */ + if (timeout == 0) { + return SDL_SemTryWait(sem); + } + + SDL_LockMutex(sem->count_lock); + ++sem->waiters_count; + retval = 0; + while ((sem->count == 0) && (retval != SDL_MUTEX_TIMEDOUT)) { + retval = SDL_CondWaitTimeout(sem->count_nonzero, sem->count_lock, timeout); + } + --sem->waiters_count; + if (retval == 0) { + --sem->count; + } + SDL_UnlockMutex(sem->count_lock); + + return retval; +} + +int SDL_SemTryWait(SDL_sem *sem) +{ + int retval; + + if (!sem) { + SDL_SetError("Passed a NULL semaphore"); + return -1; + } + + retval = SDL_MUTEX_TIMEDOUT; + SDL_LockMutex(sem->count_lock); + if (sem->count > 0) { + --sem->count; + retval = 0; + } + SDL_UnlockMutex(sem->count_lock); + + return retval; +} + +int SDL_SemWait(SDL_sem *sem) +{ + return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT); +} + +/* Returns the current count of the semaphore */ +Uint32 SDL_SemValue(SDL_sem *sem) +{ + Uint32 value; + + value = 0; + if (sem) { + SDL_LockMutex(sem->count_lock); + value = sem->count; + SDL_UnlockMutex(sem->count_lock); + } + return value; +} + +int SDL_SemPost(SDL_sem *sem) +{ + if (!sem) { + SDL_SetError("Passed a NULL semaphore"); + return -1; + } + + SDL_LockMutex(sem->count_lock); + if (sem->waiters_count > 0) { + SDL_CondSignal(sem->count_nonzero); + } + ++sem->count; + SDL_UnlockMutex(sem->count_lock); + + return 0; +} + +#endif /* SDL_THREAD_SWITCH */ diff --git a/src/thread/switch/SDL_systhread.c b/src/thread/switch/SDL_systhread.c new file mode 100644 index 000000000..b7e2b0560 --- /dev/null +++ b/src/thread/switch/SDL_systhread.c @@ -0,0 +1,87 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 Sam Lantinga + + 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_THREAD_SWITCH + +/* SWITCH thread management routines for SDL */ + +#include + +#include "SDL_error.h" +#include "SDL_thread.h" +#include "../SDL_systhread.h" + +#define STACK_SIZE 0x2000 + +static void ThreadEntry(void *argp) +{ + SDL_RunThread(*(void **) argp); +} + +int SDL_SYS_CreateThread(SDL_Thread *thread, void *args) +{ + Result res = threadCreate(&thread->handle, ThreadEntry, args, STACK_SIZE, 0x2C, -2); + if (res != 0) { + return SDL_SetError("threadCreate() failed: 0x%08X", res); + } + + res = threadStart(&thread->handle); + if (res != 0) { + return SDL_SetError("threadStart() failed: 0x%08X", res); + } + + return 0; +} + +void SDL_SYS_SetupThread(const char *name) +{ + /* Do nothing. */ +} + +SDL_threadID SDL_ThreadID(void) +{ + return (SDL_threadID) 0; +} + +void SDL_SYS_WaitThread(SDL_Thread *thread) +{ + threadWaitForExit(&thread->handle); +} + +void SDL_SYS_DetachThread(SDL_Thread *thread) +{ + // TODO ? + threadClose(&thread->handle); +} + +void SDL_SYS_KillThread(SDL_Thread *thread) +{ + // TODO ? + threadClose(&thread->handle); +} + +int SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) +{ + return 0; +} + +#endif /* SDL_THREAD_SWITCH */ diff --git a/src/thread/switch/SDL_systhread_c.h b/src/thread/switch/SDL_systhread_c.h index 112c4ead9..cc58e2c28 100644 --- a/src/thread/switch/SDL_systhread_c.h +++ b/src/thread/switch/SDL_systhread_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -21,4 +21,4 @@ #include -typedef Thread* SYS_ThreadHandle; +typedef Thread SYS_ThreadHandle; diff --git a/src/thread/switch/SDL_systls.c b/src/thread/switch/SDL_systls.c new file mode 100644 index 000000000..2472fbd60 --- /dev/null +++ b/src/thread/switch/SDL_systls.c @@ -0,0 +1,34 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga + + 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_thread_c.h" + +SDL_TLSData * +SDL_SYS_GetTLSData(void) +{ + return SDL_Generic_GetTLSData(); +} + +int +SDL_SYS_SetTLSData(SDL_TLSData *data) +{ + return SDL_Generic_SetTLSData(data); +} diff --git a/src/thread/switch/dummy.c b/src/thread/switch/dummy.c deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/timer/switch/SDL_systimer.c b/src/timer/switch/SDL_systimer.c new file mode 100644 index 000000000..5c5d209e0 --- /dev/null +++ b/src/timer/switch/SDL_systimer.c @@ -0,0 +1,78 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 Sam Lantinga + + 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" + +#ifdef SDL_TIMER_SWITCH + +#include "SDL_thread.h" +#include "SDL_timer.h" +#include "../SDL_timer_c.h" +#include + +static bool started = false; + +static Uint64 start = 0; + +void +SDL_TicksInit(void) +{ + if (started) { + return; + } + + start = SDL_GetPerformanceCounter(); + started = true; +} + +void +SDL_TicksQuit(void) +{ + started = false; +} + +Uint32 SDL_GetTicks(void) +{ + if (!started) { + SDL_TicksInit(); + } + + return (Uint32) ((SDL_GetPerformanceCounter() - start) * 1000 / SDL_GetPerformanceFrequency()); +} + +Uint64 +SDL_GetPerformanceCounter(void) +{ + return svcGetSystemTick(); +} + +Uint64 +SDL_GetPerformanceFrequency(void) +{ + return 19200000; +} + +void +SDL_Delay(Uint32 ms) +{ + svcSleepThread((Uint64) ms * 1000000); +} + +#endif /* SDL_TIMER_SWITCH */ diff --git a/src/timer/switch/dummy.c b/src/timer/switch/dummy.c deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index c8c425b6b..5659f4cdf 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -439,6 +439,7 @@ extern VideoBootStrap QNX_bootstrap; extern VideoBootStrap OFFSCREEN_bootstrap; extern VideoBootStrap OS2DIVE_bootstrap; extern VideoBootStrap OS2VMAN_bootstrap; +extern VideoBootStrap SWITCH_bootstrap; extern SDL_VideoDevice *SDL_GetVideoDevice(void); extern int SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode); diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index a0ca32243..291c78070 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -117,6 +117,9 @@ static VideoBootStrap *bootstrap[] = { &OS2DIVE_bootstrap, &OS2VMAN_bootstrap, #endif +#if SDL_VIDEO_DRIVER_SWITCH + &SWITCH_bootstrap, +#endif #if SDL_VIDEO_DRIVER_DUMMY &DUMMY_bootstrap, #endif diff --git a/src/video/switch/SDL_switchvideo.c b/src/video/switch/SDL_switchvideo.c new file mode 100644 index 000000000..c0cb8317d --- /dev/null +++ b/src/video/switch/SDL_switchvideo.c @@ -0,0 +1,168 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga + + 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_VIDEO_DRIVER_SWITCH + +/* SDL internals */ +#include "../SDL_sysvideo.h" + +#include + +#define SWITCH_DATA "_SDL_SwitchData" +#define SCREEN_WIDTH 1280 +#define SCREEN_HEIGHT 720 + +static int SWITCH_VideoInit(_THIS); + +static int SWITCH_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode); + +static void SWITCH_VideoQuit(_THIS); + +static void SWITCH_PumpEvents(_THIS); + +static int SWITCH_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, void **pixels, int *pitch); + +static int SWITCH_UpdateWindowFramebuffer(_THIS, SDL_Window *window, const SDL_Rect *rects, int numrects); + +static void SWITCH_DestroyWindowFramebuffer(_THIS, SDL_Window *window); + +static int SWITCH_Available(void) +{ + return 1; +} + +static void SWITCH_DeleteDevice(SDL_VideoDevice *device) +{ + SDL_free(device); +} + +static SDL_VideoDevice *SWITCH_CreateDevice(int devindex) +{ + SDL_VideoDevice *device; + + device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); + if (!device) { + SDL_OutOfMemory(); + return NULL; + } + + device->VideoInit = SWITCH_VideoInit; + device->VideoQuit = SWITCH_VideoQuit; + device->SetDisplayMode = SWITCH_SetDisplayMode; + device->PumpEvents = SWITCH_PumpEvents; + device->CreateWindowFramebuffer = SWITCH_CreateWindowFramebuffer; + device->UpdateWindowFramebuffer = SWITCH_UpdateWindowFramebuffer; + device->DestroyWindowFramebuffer = SWITCH_DestroyWindowFramebuffer; + + device->free = SWITCH_DeleteDevice; + + return device; +} + +VideoBootStrap SWITCH_bootstrap = { + "Switch", "Video driver for Nintendo Switch (libnx)", + SWITCH_Available, SWITCH_CreateDevice +}; + +static int SWITCH_VideoInit(_THIS) +{ + SDL_DisplayMode mode; + + gfxInitResolution(SCREEN_WIDTH, SCREEN_HEIGHT); + gfxInitDefault(); + gfxSetMode(GfxMode_LinearDouble); + + mode.format = SDL_PIXELFORMAT_ARGB8888; + mode.w = SCREEN_WIDTH; + mode.h = SCREEN_HEIGHT; + mode.refresh_rate = 60; + mode.driverdata = NULL; + if (SDL_AddBasicVideoDisplay(&mode) < 0) { + return -1; + } + + SDL_AddDisplayMode(&_this->displays[0], &mode); + + return 0; +} + +static void SWITCH_VideoQuit(_THIS) +{ + gfxExit(); +} + +static int SWITCH_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode) +{ + // TODO: use gfxConfigureResolution + return 0; +} + +static void SWITCH_PumpEvents(_THIS) +{ + // TODO +} + +typedef struct +{ +} SWITCH_WindowData; + +static int SWITCH_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, void **pixels, int *pitch) +{ + int w, h; + + //SWITCH_WindowData *data = SDL_calloc(1, sizeof(SWITCH_WindowData)); + //SDL_SetWindowData(window, SWITCH_DATA, data); + + SDL_GetWindowSize(window, &w, &h); + gfxConfigureResolution(w, h); + *pitch = w * 4; + *format = SDL_PIXELFORMAT_ABGR8888; + *pixels = gfxGetFramebuffer(NULL, NULL); + + return 0; +} + +static int SWITCH_UpdateWindowFramebuffer(_THIS, SDL_Window *window, const SDL_Rect *rects, int numrects) +{ + //SWITCH_WindowData *data = (SWITCH_WindowData *) SDL_GetWindowData(window, SWITCH_DATA); + //if (!data) { + // return SDL_SetError("Couldn't find switch data for window"); + //} + + gfxFlushBuffers(); + gfxSwapBuffers(); + gfxWaitForVsync(); + + // update fb ptr for double buffering + window->surface->pixels = gfxGetFramebuffer(NULL, NULL); + + return 0; +} + +static void SWITCH_DestroyWindowFramebuffer(_THIS, SDL_Window *window) +{ + //SWITCH_WindowData *data = (SWITCH_WindowData *) SDL_GetWindowData(window, SWITCH_DATA); + //SDL_free(data); +} + +#endif /* SDL_VIDEO_DRIVER_SWITCH */ diff --git a/src/video/switch/dummy.c b/src/video/switch/dummy.c deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/testswitch.c b/test/testswitch.c new file mode 100644 index 000000000..18e38d099 --- /dev/null +++ b/test/testswitch.c @@ -0,0 +1,69 @@ +/* + Copyright (C) 1997-2017 Sam Lantinga + + 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. +*/ + +#include +#include + +#include +#include "SDL2/SDL.h" + +#define WINDOW_WIDTH 1280 +#define WINDOW_HEIGHT 720 + +SDL_Renderer *renderer = NULL; + +int done = 0; + +int main(int argc, char *argv[]) +{ + consoleDebugInit(debugDevice_SVC); + stdout = stderr; + + SDL_Window *window; + + if (SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer) < 0) { + printf("SDL_CreateWindowAndRenderer: %s\n", SDL_GetError()); + return -1; + } + + SDL_Event event; + + printf("entering main loop\n"); + + while (!done) { + + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT || event.type == SDL_KEYDOWN) { + done = 1; + } + } + + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + + SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); + SDL_Rect r = {0, 0, 64, 64}; + SDL_RenderFillRect(renderer, &r); + + SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); + SDL_Rect g = {64, 0, 64, 64}; + SDL_RenderFillRect(renderer, &g); + + SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); + SDL_Rect b = {128, 0, 64, 64}; + SDL_RenderFillRect(renderer, &b); + + SDL_RenderPresent(renderer); + } + + return 0; +}