diff --git a/audio/drivers/switch_nx_thread_audio.c b/audio/drivers/switch_nx_thread_audio.c
index d6acaa73ce..72a8fc4869 100644
--- a/audio/drivers/switch_nx_thread_audio.c
+++ b/audio/drivers/switch_nx_thread_audio.c
@@ -1,358 +1,358 @@
-/* RetroArch - A frontend for libretro.
- * Copyright (C) 2018 - misson2000
- * Copyright (C) 2018 - m4xw
- * Copyright (C) 2018 - lifajucejo
- *
- * 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 "../audio_driver.h"
-#include "../../verbosity.h"
-
-#include "../../tasks/tasks_internal.h"
-
-#define THREAD_STACK_SIZE (1024 * 8)
-
-#define AUDIO_THREAD_CPU 2
-
-#define CHANNELCOUNT 2
-#define BYTESPERSAMPLE sizeof(uint16_t)
-#define SAMPLE_SIZE (CHANNELCOUNT * BYTESPERSAMPLE)
-
-#define AUDIO_BUFFER_COUNT 2
-
-static inline void lockMutex(Mutex* mtx)
-{
- mutexLock(mtx);
-}
-
-typedef struct
-{
- fifo_buffer_t* fifo;
- Mutex fifoLock;
- CondVar cond;
- Mutex condLock;
-
- size_t fifoSize;
-
- volatile bool running;
- bool nonblocking;
- bool is_paused;
-
- AudioOutBuffer buffer[AUDIO_BUFFER_COUNT];
- Thread thread;
-
- unsigned latency;
- uint32_t sampleRate;
-} switch_thread_audio_t;
-
-static void mainLoop(void* data)
-{
- switch_thread_audio_t* swa = (switch_thread_audio_t*)data;
-
- if (!swa)
- return;
-
- RARCH_LOG("[Audio]: start mainLoop cpu %u tid %u\n", svcGetCurrentProcessorNumber(), swa->thread.handle);
-
- for (int i = 0; i < AUDIO_BUFFER_COUNT; i++)
- {
- swa->buffer[i].next = NULL; /* Unused */
- swa->buffer[i].buffer_size = swa->fifoSize;
- swa->buffer[i].buffer = memalign(0x1000, swa->buffer[i].buffer_size);
- swa->buffer[i].data_size = swa->buffer[i].buffer_size;
- swa->buffer[i].data_offset = 0;
-
- memset(swa->buffer[i].buffer, 0, swa->buffer[i].buffer_size);
- audoutAppendAudioOutBuffer(&swa->buffer[i]);
- }
-
- AudioOutBuffer* released_out_buffer = NULL;
- u32 released_out_count;
- Result rc;
-
- while (swa->running)
- {
- if (!released_out_buffer)
- {
- rc = audoutWaitPlayFinish(&released_out_buffer, &released_out_count, U64_MAX);
- if (R_FAILED(rc))
- {
- swa->running = false;
- RARCH_LOG("[Audio]: audoutGetReleasedAudioOutBuffer failed: %d\n", (int)rc);
- break;
- }
- released_out_buffer->data_size = 0;
- }
-
- size_t bufAvail = released_out_buffer->buffer_size - released_out_buffer->data_size;
-
- lockMutex(&swa->fifoLock);
-
- size_t avail = fifo_read_avail(swa->fifo);
- size_t to_write = MIN(avail, bufAvail);
- if (to_write > 0)
- fifo_read(swa->fifo, ((u8*)released_out_buffer->buffer) + released_out_buffer->data_size, to_write);
-
- mutexUnlock(&swa->fifoLock);
- condvarWakeAll(&swa->cond);
-
- released_out_buffer->data_size += to_write;
- if (released_out_buffer->data_size >= released_out_buffer->buffer_size / 2)
- {
- rc = audoutAppendAudioOutBuffer(released_out_buffer);
- if (R_FAILED(rc))
- {
- RARCH_LOG("[Audio]: audoutAppendAudioOutBuffer failed: %d\n", (int)rc);
- }
- released_out_buffer = NULL;
- }
- else
- svcSleepThread(16000000); /* 16ms */
- }
-}
-
-static void *switch_thread_audio_init(const char *device, unsigned rate, unsigned latency, unsigned block_frames, unsigned *new_rate)
-{
- (void)device;
-
- switch_thread_audio_t *swa = (switch_thread_audio_t *)calloc(1, sizeof(switch_thread_audio_t));
-
- if (!swa)
- return NULL;
-
- swa->running = true;
- swa->nonblocking = true;
- swa->is_paused = true;
- swa->latency = MAX(latency, 8);
-
- Result rc = audoutInitialize();
- if (R_FAILED(rc))
- {
- RARCH_LOG("[Audio]: audio init failed %d\n", (int)rc);
- return NULL;
- }
-
- rc = audoutStartAudioOut();
- if (R_FAILED(rc))
- {
- RARCH_LOG("[Audio]: audio start init failed: %d\n", (int)rc);
- return NULL;
- }
-
- swa->sampleRate = audoutGetSampleRate();
- *new_rate = swa->sampleRate;
-
- mutexInit(&swa->fifoLock);
- swa->fifoSize = (swa->sampleRate * SAMPLE_SIZE * swa->latency) / 1000;
- swa->fifo = fifo_new(swa->fifoSize);
-
- condvarInit(&swa->cond);
-
- RARCH_LOG("[Audio]: switch_thread_audio_init device %s requested rate %hu rate %hu latency %hu block_frames %hu fifoSize %lu\n",
- device, rate, swa->sampleRate, swa->latency, block_frames, swa->fifoSize);
-
- u32 prio;
- svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
- rc = threadCreate(&swa->thread, &mainLoop, (void*)swa, THREAD_STACK_SIZE, prio + 1, AUDIO_THREAD_CPU);
-
- if (R_FAILED(rc))
- {
- RARCH_LOG("[Audio]: thread creation failed create %u\n", swa->thread.handle);
- swa->running = false;
- return NULL;
- }
-
- if (R_FAILED(threadStart(&swa->thread)))
- {
- RARCH_LOG("[Audio]: thread creation failed start %u\n", swa->thread.handle);
- threadClose(&swa->thread);
- swa->running = false;
- return NULL;
- }
-
- return swa;
-}
-
-static bool switch_thread_audio_start(void *data, bool is_shutdown)
-{
- /* RARCH_LOG("[Audio]: switch_thread_audio_start\n"); */
- switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
-
- if (!swa)
- return false;
-
- swa->is_paused = false;
- return true;
-}
-
-static bool switch_thread_audio_stop(void *data)
-{
- switch_thread_audio_t* swa = (switch_thread_audio_t*)data;
-
- if (!swa)
- return false;
-
- swa->is_paused = true;
- return true;
-}
-
-static void switch_thread_audio_free(void *data)
-{
- switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
-
- if (!swa)
- return;
-
- if (swa->running)
- {
- swa->running = false;
- threadWaitForExit(&swa->thread);
- threadClose(&swa->thread);
- }
-
- audoutStopAudioOut();
- audoutExit();
-
- if (swa->fifo)
- {
- fifo_free(swa->fifo);
- swa->fifo = NULL;
- }
-
- for (int i = 0; i < AUDIO_BUFFER_COUNT; i++)
- free(swa->buffer[i].buffer);
-
- free(swa);
- swa = NULL;
-}
-
-static ssize_t switch_thread_audio_write(void *data, const void *buf, size_t size)
-{
- switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
-
- if (!swa || !swa->running)
- return 0;
-
- size_t avail;
- size_t written;
-
- if (swa->nonblocking)
- {
- lockMutex(&swa->fifoLock);
- avail = fifo_write_avail(swa->fifo);
- written = MIN(avail, size);
- if (written > 0)
- {
- fifo_write(swa->fifo, buf, written);
- }
- mutexUnlock(&swa->fifoLock);
- }
- else
- {
- written = 0;
- while (written < size && swa->running)
- {
- lockMutex(&swa->fifoLock);
- avail = fifo_write_avail(swa->fifo);
- if (avail == 0)
- {
- mutexUnlock(&swa->fifoLock);
- lockMutex(&swa->condLock);
- if (swa->running)
- condvarWait(&swa->cond, &swa->condLock);
- mutexUnlock(&swa->condLock);
- }
- else
- {
- size_t write_amt = MIN(size - written, avail);
- fifo_write(swa->fifo, (const char*)buf + written, write_amt);
- mutexUnlock(&swa->fifoLock);
- written += write_amt;
- }
- }
- }
-
- return written;
-}
-
-static bool switch_thread_audio_alive(void *data)
-{
- switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
-
- if (!swa)
- return false;
-
- return !swa->is_paused;
-}
-
-static void switch_thread_audio_set_nonblock_state(void *data, bool state)
-{
- switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
-
- if (swa)
- swa->nonblocking = state;
-}
-
-static bool switch_thread_audio_use_float(void *data)
-{
- (void)data;
- return false;
-}
-
-static size_t switch_thread_audio_write_avail(void *data)
-{
- switch_thread_audio_t* swa = (switch_thread_audio_t*)data;
-
- lockMutex(&swa->fifoLock);
- size_t val = fifo_write_avail(swa->fifo);
- mutexUnlock(&swa->fifoLock);
-
- return val;
-}
-
-size_t switch_thread_audio_buffer_size(void *data)
-{
- switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
-
- if (!swa)
- return 0;
-
- return swa->fifoSize;
-}
-
-audio_driver_t audio_switch_thread = {
- switch_thread_audio_init,
- switch_thread_audio_write,
- switch_thread_audio_stop,
- switch_thread_audio_start,
- switch_thread_audio_alive,
- switch_thread_audio_set_nonblock_state,
- switch_thread_audio_free,
- switch_thread_audio_use_float,
- "switch_thread",
- NULL, /* device_list_new */
- NULL, /* device_list_free */
- switch_thread_audio_write_avail,
- switch_thread_audio_buffer_size
-};
-
-/* vim: set ts=6 sw=6 sts=6: */
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2018 - misson2000
+ * Copyright (C) 2018 - m4xw
+ * Copyright (C) 2018 - lifajucejo
+ *
+ * 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 "../audio_driver.h"
+#include "../../verbosity.h"
+
+#include "../../tasks/tasks_internal.h"
+
+#define THREAD_STACK_SIZE (1024 * 8)
+
+#define AUDIO_THREAD_CPU 2
+
+#define CHANNELCOUNT 2
+#define BYTESPERSAMPLE sizeof(uint16_t)
+#define SAMPLE_SIZE (CHANNELCOUNT * BYTESPERSAMPLE)
+
+#define AUDIO_BUFFER_COUNT 2
+
+static inline void lockMutex(Mutex* mtx)
+{
+ mutexLock(mtx);
+}
+
+typedef struct
+{
+ fifo_buffer_t* fifo;
+ Mutex fifoLock;
+ CondVar cond;
+ Mutex condLock;
+
+ size_t fifoSize;
+
+ volatile bool running;
+ bool nonblocking;
+ bool is_paused;
+
+ AudioOutBuffer buffer[AUDIO_BUFFER_COUNT];
+ Thread thread;
+
+ unsigned latency;
+ uint32_t sampleRate;
+} switch_thread_audio_t;
+
+static void mainLoop(void* data)
+{
+ switch_thread_audio_t* swa = (switch_thread_audio_t*)data;
+
+ if (!swa)
+ return;
+
+ RARCH_LOG("[Audio]: start mainLoop cpu %u tid %u\n", svcGetCurrentProcessorNumber(), swa->thread.handle);
+
+ for (int i = 0; i < AUDIO_BUFFER_COUNT; i++)
+ {
+ swa->buffer[i].next = NULL; /* Unused */
+ swa->buffer[i].buffer_size = swa->fifoSize;
+ swa->buffer[i].buffer = memalign(0x1000, swa->buffer[i].buffer_size);
+ swa->buffer[i].data_size = swa->buffer[i].buffer_size;
+ swa->buffer[i].data_offset = 0;
+
+ memset(swa->buffer[i].buffer, 0, swa->buffer[i].buffer_size);
+ audoutAppendAudioOutBuffer(&swa->buffer[i]);
+ }
+
+ AudioOutBuffer* released_out_buffer = NULL;
+ u32 released_out_count;
+ Result rc;
+
+ while (swa->running)
+ {
+ if (!released_out_buffer)
+ {
+ rc = audoutWaitPlayFinish(&released_out_buffer, &released_out_count, U64_MAX);
+ if (R_FAILED(rc))
+ {
+ swa->running = false;
+ RARCH_LOG("[Audio]: audoutGetReleasedAudioOutBuffer failed: %d\n", (int)rc);
+ break;
+ }
+ released_out_buffer->data_size = 0;
+ }
+
+ size_t bufAvail = released_out_buffer->buffer_size - released_out_buffer->data_size;
+
+ lockMutex(&swa->fifoLock);
+
+ size_t avail = fifo_read_avail(swa->fifo);
+ size_t to_write = MIN(avail, bufAvail);
+ if (to_write > 0)
+ fifo_read(swa->fifo, ((u8*)released_out_buffer->buffer) + released_out_buffer->data_size, to_write);
+
+ mutexUnlock(&swa->fifoLock);
+ condvarWakeAll(&swa->cond);
+
+ released_out_buffer->data_size += to_write;
+ if (released_out_buffer->data_size >= released_out_buffer->buffer_size / 2)
+ {
+ rc = audoutAppendAudioOutBuffer(released_out_buffer);
+ if (R_FAILED(rc))
+ {
+ RARCH_LOG("[Audio]: audoutAppendAudioOutBuffer failed: %d\n", (int)rc);
+ }
+ released_out_buffer = NULL;
+ }
+ else
+ svcSleepThread(16000000); /* 16ms */
+ }
+}
+
+static void *switch_thread_audio_init(const char *device, unsigned rate, unsigned latency, unsigned block_frames, unsigned *new_rate)
+{
+ (void)device;
+
+ switch_thread_audio_t *swa = (switch_thread_audio_t *)calloc(1, sizeof(switch_thread_audio_t));
+
+ if (!swa)
+ return NULL;
+
+ swa->running = true;
+ swa->nonblocking = true;
+ swa->is_paused = true;
+ swa->latency = MAX(latency, 8);
+
+ Result rc = audoutInitialize();
+ if (R_FAILED(rc))
+ {
+ RARCH_LOG("[Audio]: audio init failed %d\n", (int)rc);
+ return NULL;
+ }
+
+ rc = audoutStartAudioOut();
+ if (R_FAILED(rc))
+ {
+ RARCH_LOG("[Audio]: audio start init failed: %d\n", (int)rc);
+ return NULL;
+ }
+
+ swa->sampleRate = audoutGetSampleRate();
+ *new_rate = swa->sampleRate;
+
+ mutexInit(&swa->fifoLock);
+ swa->fifoSize = (swa->sampleRate * SAMPLE_SIZE * swa->latency) / 1000;
+ swa->fifo = fifo_new(swa->fifoSize);
+
+ condvarInit(&swa->cond);
+
+ RARCH_LOG("[Audio]: switch_thread_audio_init device %s requested rate %hu rate %hu latency %hu block_frames %hu fifoSize %lu\n",
+ device, rate, swa->sampleRate, swa->latency, block_frames, swa->fifoSize);
+
+ u32 prio;
+ svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
+ rc = threadCreate(&swa->thread, &mainLoop, (void*)swa, THREAD_STACK_SIZE, prio + 1, AUDIO_THREAD_CPU);
+
+ if (R_FAILED(rc))
+ {
+ RARCH_LOG("[Audio]: thread creation failed create %u\n", swa->thread.handle);
+ swa->running = false;
+ return NULL;
+ }
+
+ if (R_FAILED(threadStart(&swa->thread)))
+ {
+ RARCH_LOG("[Audio]: thread creation failed start %u\n", swa->thread.handle);
+ threadClose(&swa->thread);
+ swa->running = false;
+ return NULL;
+ }
+
+ return swa;
+}
+
+static bool switch_thread_audio_start(void *data, bool is_shutdown)
+{
+ /* RARCH_LOG("[Audio]: switch_thread_audio_start\n"); */
+ switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
+
+ if (!swa)
+ return false;
+
+ swa->is_paused = false;
+ return true;
+}
+
+static bool switch_thread_audio_stop(void *data)
+{
+ switch_thread_audio_t* swa = (switch_thread_audio_t*)data;
+
+ if (!swa)
+ return false;
+
+ swa->is_paused = true;
+ return true;
+}
+
+static void switch_thread_audio_free(void *data)
+{
+ switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
+
+ if (!swa)
+ return;
+
+ if (swa->running)
+ {
+ swa->running = false;
+ threadWaitForExit(&swa->thread);
+ threadClose(&swa->thread);
+ }
+
+ audoutStopAudioOut();
+ audoutExit();
+
+ if (swa->fifo)
+ {
+ fifo_free(swa->fifo);
+ swa->fifo = NULL;
+ }
+
+ for (int i = 0; i < AUDIO_BUFFER_COUNT; i++)
+ free(swa->buffer[i].buffer);
+
+ free(swa);
+ swa = NULL;
+}
+
+static ssize_t switch_thread_audio_write(void *data, const void *buf, size_t size)
+{
+ switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
+
+ if (!swa || !swa->running)
+ return 0;
+
+ size_t avail;
+ size_t written;
+
+ if (swa->nonblocking)
+ {
+ lockMutex(&swa->fifoLock);
+ avail = fifo_write_avail(swa->fifo);
+ written = MIN(avail, size);
+ if (written > 0)
+ {
+ fifo_write(swa->fifo, buf, written);
+ }
+ mutexUnlock(&swa->fifoLock);
+ }
+ else
+ {
+ written = 0;
+ while (written < size && swa->running)
+ {
+ lockMutex(&swa->fifoLock);
+ avail = fifo_write_avail(swa->fifo);
+ if (avail == 0)
+ {
+ mutexUnlock(&swa->fifoLock);
+ lockMutex(&swa->condLock);
+ if (swa->running)
+ condvarWait(&swa->cond, &swa->condLock);
+ mutexUnlock(&swa->condLock);
+ }
+ else
+ {
+ size_t write_amt = MIN(size - written, avail);
+ fifo_write(swa->fifo, (const char*)buf + written, write_amt);
+ mutexUnlock(&swa->fifoLock);
+ written += write_amt;
+ }
+ }
+ }
+
+ return written;
+}
+
+static bool switch_thread_audio_alive(void *data)
+{
+ switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
+
+ if (!swa)
+ return false;
+
+ return !swa->is_paused;
+}
+
+static void switch_thread_audio_set_nonblock_state(void *data, bool state)
+{
+ switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
+
+ if (swa)
+ swa->nonblocking = state;
+}
+
+static bool switch_thread_audio_use_float(void *data)
+{
+ (void)data;
+ return false;
+}
+
+static size_t switch_thread_audio_write_avail(void *data)
+{
+ switch_thread_audio_t* swa = (switch_thread_audio_t*)data;
+
+ lockMutex(&swa->fifoLock);
+ size_t val = fifo_write_avail(swa->fifo);
+ mutexUnlock(&swa->fifoLock);
+
+ return val;
+}
+
+size_t switch_thread_audio_buffer_size(void *data)
+{
+ switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
+
+ if (!swa)
+ return 0;
+
+ return swa->fifoSize;
+}
+
+audio_driver_t audio_switch_thread = {
+ switch_thread_audio_init,
+ switch_thread_audio_write,
+ switch_thread_audio_stop,
+ switch_thread_audio_start,
+ switch_thread_audio_alive,
+ switch_thread_audio_set_nonblock_state,
+ switch_thread_audio_free,
+ switch_thread_audio_use_float,
+ "switch_thread",
+ NULL, /* device_list_new */
+ NULL, /* device_list_free */
+ switch_thread_audio_write_avail,
+ switch_thread_audio_buffer_size
+};
+
+/* vim: set ts=6 sw=6 sts=6: */
diff --git a/frontend/drivers/platform_switch.c b/frontend/drivers/platform_switch.c
index e1250481f9..6c77b6d1d2 100644
--- a/frontend/drivers/platform_switch.c
+++ b/frontend/drivers/platform_switch.c
@@ -1,737 +1,737 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#include
-
-#include
-
-#ifdef HAVE_CONFIG_H
-#include "../../config.h"
-#endif
-
-#ifndef IS_SALAMANDER
-#include
-#endif
-
-#include "../frontend_driver.h"
-#include "../../verbosity.h"
-#include "../../defaults.h"
-#include "../../paths.h"
-#include "../../retroarch.h"
-#include "../../file_path_special.h"
-#include "../../audio/audio_driver.h"
-
-#ifndef IS_SALAMANDER
-#ifdef HAVE_MENU
-#include "../../menu/menu_driver.h"
-#endif
-#endif
-
-static enum frontend_fork switch_fork_mode = FRONTEND_FORK_NONE;
-static const char *elf_path_cst = "/switch/retroarch_switch.nro";
-
-static uint64_t frontend_switch_get_mem_used(void);
-
-// Splash
-static uint32_t *splashData = NULL;
-
-// switch_gfx.c protypes, we really need a header
-extern void gfx_slow_swizzling_blit(uint32_t *buffer, uint32_t *image, int w, int h, int tx, int ty, bool blend);
-
-static void get_first_valid_core(char *path_return)
-{
- DIR *dir;
- struct dirent *ent;
- const char *extension = ".nro";
-
- path_return[0] = '\0';
-
- dir = opendir("/retroarch/cores");
- if (dir != NULL)
- {
- while (ent = readdir(dir))
- {
- if (ent == NULL)
- break;
- if (strlen(ent->d_name) > strlen(extension) && !strcmp(ent->d_name + strlen(ent->d_name) - strlen(extension), extension))
- {
- strcpy(path_return, "/retroarch/cores");
- strcat(path_return, "/");
- strcat(path_return, ent->d_name);
- break;
- }
- }
- closedir(dir);
- }
-}
-
-static void frontend_switch_get_environment_settings(int *argc, char *argv[], void *args, void *params_data)
-{
- (void)args;
-
-#ifndef IS_SALAMANDER
-#if defined(HAVE_LOGGER)
- logger_init();
-#elif defined(HAVE_FILE_LOGGER)
- retro_main_log_file_init("/retroarch-log.txt");
-#endif
-#endif
-
- fill_pathname_basedir(g_defaults.dirs[DEFAULT_DIR_PORT], "/retroarch/retroarch_switch.nro", sizeof(g_defaults.dirs[DEFAULT_DIR_PORT]));
- RARCH_LOG("port dir: [%s]\n", g_defaults.dirs[DEFAULT_DIR_PORT]);
-
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], g_defaults.dirs[DEFAULT_DIR_PORT],
- "downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
-
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], g_defaults.dirs[DEFAULT_DIR_PORT],
- "media", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
-
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], g_defaults.dirs[DEFAULT_DIR_PORT],
- "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
-
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], g_defaults.dirs[DEFAULT_DIR_CORE],
- "info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
-
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], g_defaults.dirs[DEFAULT_DIR_CORE],
- "savestates", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE]));
-
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], g_defaults.dirs[DEFAULT_DIR_CORE],
- "savefiles", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM]));
-
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], g_defaults.dirs[DEFAULT_DIR_CORE],
- "system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM]));
-
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], g_defaults.dirs[DEFAULT_DIR_CORE],
- "playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
-
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], g_defaults.dirs[DEFAULT_DIR_PORT],
- "config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG]));
-
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP], g_defaults.dirs[DEFAULT_DIR_PORT],
- "config/remaps", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP]));
-
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], g_defaults.dirs[DEFAULT_DIR_PORT],
- "filters", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP]));
-
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], g_defaults.dirs[DEFAULT_DIR_PORT],
- "database/rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE]));
-
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CURSOR], g_defaults.dirs[DEFAULT_DIR_PORT],
- "database/cursors", sizeof(g_defaults.dirs[DEFAULT_DIR_CURSOR]));
-
- fill_pathname_join(g_defaults.path.config, g_defaults.dirs[DEFAULT_DIR_PORT],
- file_path_str(FILE_PATH_MAIN_CONFIG), sizeof(g_defaults.path.config));
-}
-
-static void frontend_switch_deinit(void *data)
-{
- (void)data;
-
-#if defined(HAVE_LIBNX) && defined(NXLINK) // Else freeze on exit
- socketExit();
-#endif
-
- // Splash
- if (splashData)
- {
- free(splashData);
- splashData = NULL;
- }
-
- gfxExit();
-}
-
-static void frontend_switch_exec(const char *path, bool should_load_game)
-{
- char game_path[PATH_MAX];
- const char *arg_data[3];
- char error_string[200 + PATH_MAX];
- int args = 0;
- int error = 0;
-
- game_path[0] = NULL;
- arg_data[0] = NULL;
-
- arg_data[args] = elf_path_cst;
- arg_data[args + 1] = NULL;
- args++;
-
- RARCH_LOG("Attempt to load core: [%s].\n", path);
-#ifndef IS_SALAMANDER
- if (should_load_game && !path_is_empty(RARCH_PATH_CONTENT))
- {
- strcpy(game_path, path_get(RARCH_PATH_CONTENT));
- arg_data[args] = game_path;
- arg_data[args + 1] = NULL;
- args++;
- RARCH_LOG("content path: [%s].\n", path_get(RARCH_PATH_CONTENT));
- }
-#endif
-
- if (path && path[0])
- {
-#ifdef IS_SALAMANDER
- struct stat sbuff;
- bool file_exists;
-
- file_exists = stat(path, &sbuff) == 0;
- if (!file_exists)
- {
- char core_path[PATH_MAX];
-
- /* find first valid core and load it if the target core doesnt exist */
- get_first_valid_core(&core_path[0]);
-
- if (core_path[0] == '\0')
- {
- /*errorInit(&error_dialog, ERROR_TEXT, CFG_LANGUAGE_EN);
- errorText(&error_dialog, "There are no cores installed, install a core to continue.");
- errorDisp(&error_dialog);*/
- svcExitProcess();
- }
- }
-#endif
- char *argBuffer = (char *)malloc(PATH_MAX);
- if (should_load_game)
- {
- snprintf(argBuffer, PATH_MAX, "%s \"%s\"", path, game_path);
- }
- else
- {
- snprintf(argBuffer, PATH_MAX, "%s", path);
- }
-
- envSetNextLoad(path, argBuffer);
- }
-}
-
-#ifndef IS_SALAMANDER
-static bool frontend_switch_set_fork(enum frontend_fork fork_mode)
-{
- switch (fork_mode)
- {
- case FRONTEND_FORK_CORE:
- RARCH_LOG("FRONTEND_FORK_CORE\n");
- switch_fork_mode = fork_mode;
- break;
- case FRONTEND_FORK_CORE_WITH_ARGS:
- RARCH_LOG("FRONTEND_FORK_CORE_WITH_ARGS\n");
- switch_fork_mode = fork_mode;
- break;
- case FRONTEND_FORK_RESTART:
- RARCH_LOG("FRONTEND_FORK_RESTART\n");
- /* NOTE: We don't implement Salamander, so just turn
- this into FRONTEND_FORK_CORE. */
- switch_fork_mode = FRONTEND_FORK_CORE;
- break;
- case FRONTEND_FORK_NONE:
- default:
- return false;
- }
-
- return true;
-}
-#endif
-
-static void frontend_switch_exitspawn(char *s, size_t len)
-{
- bool should_load_game = false;
-#ifndef IS_SALAMANDER
- if (switch_fork_mode == FRONTEND_FORK_NONE)
- return;
-
- switch (switch_fork_mode)
- {
- case FRONTEND_FORK_CORE_WITH_ARGS:
- should_load_game = true;
- break;
- default:
- break;
- }
-#endif
- frontend_switch_exec(s, should_load_game);
-}
-
-static void frontend_switch_shutdown(bool unused)
-{
- (void)unused;
-}
-
-void argb_to_rgba8(uint32_t *buff, uint32_t height, uint32_t width)
-{
- // Convert
- for (uint32_t h = 0; h < height; h++)
- {
- for (uint32_t w = 0; w < width; w++)
- {
- uint32_t offset = (h * width) + w;
- uint32_t c = buff[offset];
-
- uint32_t a = (uint32_t)((c & 0xff000000) >> 24);
- uint32_t r = (uint32_t)((c & 0x00ff0000) >> 16);
- uint32_t g = (uint32_t)((c & 0x0000ff00) >> 8);
- uint32_t b = (uint32_t)(c & 0x000000ff);
-
- buff[offset] = RGBA8(r, g, b, a);
- }
- }
-}
-
-void frontend_switch_showsplash()
-{
- printf("[Splash] Showing splashScreen\n");
-
- if (splashData)
- {
- uint32_t width, height;
- width = height = 0;
-
- uint32_t *frambuffer = (uint32_t *)gfxGetFramebuffer(&width, &height);
-
- gfx_slow_swizzling_blit(frambuffer, splashData, width, height, 0, 0, false);
-
- gfxFlushBuffers();
- gfxSwapBuffers();
- gfxWaitForVsync();
- }
-}
-
-// From rpng_test.c
-bool rpng_load_image_argb(const char *path, uint32_t **data, unsigned *width, unsigned *height)
-{
- int retval;
- size_t file_len;
- bool ret = true;
- rpng_t *rpng = NULL;
- void *ptr = NULL;
-
- struct nbio_t *handle = (struct nbio_t *)nbio_open(path, NBIO_READ);
-
- if (!handle)
- goto end;
-
- nbio_begin_read(handle);
-
- while (!nbio_iterate(handle))
- svcSleepThread(3);
-
- ptr = nbio_get_ptr(handle, &file_len);
-
- if (!ptr)
- {
- ret = false;
- goto end;
- }
-
- rpng = rpng_alloc();
-
- if (!rpng)
- {
- ret = false;
- goto end;
- }
-
- if (!rpng_set_buf_ptr(rpng, (uint8_t *)ptr))
- {
- ret = false;
- goto end;
- }
-
- if (!rpng_start(rpng))
- {
- ret = false;
- goto end;
- }
-
- while (rpng_iterate_image(rpng))
- svcSleepThread(3);
-
- if (!rpng_is_valid(rpng))
- {
- ret = false;
- goto end;
- }
-
- do
- {
- retval = rpng_process_image(rpng, (void **)data, file_len, width, height);
- svcSleepThread(3);
- } while (retval == IMAGE_PROCESS_NEXT);
-
- if (retval == IMAGE_PROCESS_ERROR || retval == IMAGE_PROCESS_ERROR_END)
- ret = false;
-
-end:
- if (handle)
- nbio_free(handle);
-
- if (rpng)
- rpng_free(rpng);
-
- rpng = NULL;
-
- if (!ret)
- free(*data);
-
- return ret;
-}
-
-int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
-{
- svcSleepThread(rqtp->tv_nsec + (rqtp->tv_sec * 1000000000));
- return 0;
-}
-
-long sysconf(int name)
-{
- switch (name)
- {
- case 8:
- return 0x1000;
- }
- return -1;
-}
-
-ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize)
-{
- return -1;
-}
-
-// Taken from glibc
-char *realpath(const char *name, char *resolved)
-{
- char *rpath, *dest, *extra_buf = NULL;
- const char *start, *end, *rpath_limit;
- long int path_max;
- int num_links = 0;
-
- if (name == NULL)
- {
- /* As per Single Unix Specification V2 we must return an error if
- either parameter is a null pointer. We extend this to allow
- the RESOLVED parameter to be NULL in case the we are expected to
- allocate the room for the return value. */
- return NULL;
- }
-
- if (name[0] == '\0')
- {
- /* As per Single Unix Specification V2 we must return an error if
- the name argument points to an empty string. */
- return NULL;
- }
-
-#ifdef PATH_MAX
- path_max = PATH_MAX;
-#else
- path_max = pathconf(name, _PC_PATH_MAX);
- if (path_max <= 0)
- path_max = 1024;
-#endif
-
- if (resolved == NULL)
- {
- rpath = malloc(path_max);
- if (rpath == NULL)
- return NULL;
- }
- else
- rpath = resolved;
- rpath_limit = rpath + path_max;
-
- if (name[0] != '/')
- {
- if (!getcwd(rpath, path_max))
- {
- rpath[0] = '\0';
- goto error;
- }
- dest = memchr(rpath, '\0', path_max);
- }
- else
- {
- rpath[0] = '/';
- dest = rpath + 1;
- }
-
- for (start = end = name; *start; start = end)
- {
- int n;
-
- /* Skip sequence of multiple path-separators. */
- while (*start == '/')
- ++start;
-
- /* Find end of path component. */
- for (end = start; *end && *end != '/'; ++end)
- /* Nothing. */;
-
- if (end - start == 0)
- break;
- else if (end - start == 1 && start[0] == '.')
- /* nothing */;
- else if (end - start == 2 && start[0] == '.' && start[1] == '.')
- {
- /* Back up to previous component, ignore if at root already. */
- if (dest > rpath + 1)
- while ((--dest)[-1] != '/')
- ;
- }
- else
- {
- size_t new_size;
-
- if (dest[-1] != '/')
- *dest++ = '/';
-
- if (dest + (end - start) >= rpath_limit)
- {
- ptrdiff_t dest_offset = dest - rpath;
- char *new_rpath;
-
- if (resolved)
- {
- if (dest > rpath + 1)
- dest--;
- *dest = '\0';
- goto error;
- }
- new_size = rpath_limit - rpath;
- if (end - start + 1 > path_max)
- new_size += end - start + 1;
- else
- new_size += path_max;
- new_rpath = (char *)realloc(rpath, new_size);
- if (new_rpath == NULL)
- goto error;
- rpath = new_rpath;
- rpath_limit = rpath + new_size;
-
- dest = rpath + dest_offset;
- }
-
- dest = memcpy(dest, start, end - start);
- *dest = '\0';
- }
- }
- if (dest > rpath + 1 && dest[-1] == '/')
- --dest;
- *dest = '\0';
-
- return rpath;
-
-error:
- if (resolved == NULL)
- free(rpath);
- return NULL;
-}
-
-// runloop_get_system_info isnt initialized that early..
-extern void retro_get_system_info(struct retro_system_info *info);
-
-static void frontend_switch_init(void *data)
-{
- (void)data;
-
- // Init Resolution before initDefault
- gfxInitResolution(1280, 720);
-
- gfxInitDefault();
- gfxSetMode(GfxMode_TiledDouble);
-
- gfxConfigureTransform(0);
-
-#if defined(HAVE_LIBNX) && defined(NXLINK)
- socketInitializeDefault();
- nxlinkStdio();
-#ifndef IS_SALAMANDER
- verbosity_enable();
-#endif
-#endif
-
- rarch_system_info_t *sys_info = runloop_get_system_info();
- retro_get_system_info(sys_info);
-
- const char *core_name = NULL;
-
- printf("[Video]: Video initialized\n");
-
- uint32_t width, height;
- width = height = 0;
-
- // Load splash
- if (!splashData)
- {
- if (sys_info)
- {
- core_name = sys_info->info.library_name;
- char *full_core_splash_path = (char *)malloc(PATH_MAX);
- snprintf(full_core_splash_path, PATH_MAX, "/retroarch/rgui/splash/%s.png", core_name);
-
- rpng_load_image_argb((const char *)full_core_splash_path, &splashData, &width, &height);
- if (splashData)
- {
- argb_to_rgba8(splashData, height, width);
- frontend_switch_showsplash();
- }
- else
- {
- rpng_load_image_argb("/retroarch/rgui/splash/RetroArch.png", &splashData, &width, &height);
- if (splashData)
- {
- argb_to_rgba8(splashData, height, width);
- frontend_switch_showsplash();
- }
- }
-
- free(full_core_splash_path);
- }
- else
- {
- rpng_load_image_argb("/retroarch/rgui/splash/RetroArch.png", &splashData, &width, &height);
- if (splashData)
- {
- argb_to_rgba8(splashData, height, width);
- frontend_switch_showsplash();
- }
- }
- }
- else
- {
- frontend_switch_showsplash();
- }
-}
-
-static int frontend_switch_get_rating(void)
-{
- return 1000;
-}
-
-enum frontend_architecture frontend_switch_get_architecture(void)
-{
- return FRONTEND_ARCH_ARMV8;
-}
-
-static int frontend_switch_parse_drive_list(void *data, bool load_content)
-{
-#ifndef IS_SALAMANDER
- file_list_t *list = (file_list_t *)data;
- enum msg_hash_enums enum_idx = load_content ? MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR : MSG_UNKNOWN;
-
- if (!list)
- return -1;
-
- menu_entries_append_enum(list, "/", msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0);
-#endif
-
- return 0;
-}
-
-static uint64_t frontend_switch_get_mem_total(void)
-{
- uint64_t memoryTotal = 0;
- svcGetInfo(&memoryTotal, 6, CUR_PROCESS_HANDLE, 0); // avaiable
- memoryTotal += frontend_switch_get_mem_used();
-
- return memoryTotal;
-}
-
-static uint64_t frontend_switch_get_mem_used(void)
-{
- uint64_t memoryUsed = 0;
- svcGetInfo(&memoryUsed, 7, CUR_PROCESS_HANDLE, 0); // used
-
- return memoryUsed;
-}
-
-static enum frontend_powerstate frontend_switch_get_powerstate(int *seconds, int *percent)
-{
- // This is fine monkaS
- return FRONTEND_POWERSTATE_CHARGED;
-}
-
-static void frontend_switch_get_os(char *s, size_t len, int *major, int *minor)
-{
- strlcpy(s, "Horizon OS", len);
-
- // There is pretty sure a better way, but this will do just fine
- if (kernelAbove500())
- {
- *major = 5;
- *minor = 0;
- }
- else if (kernelAbove400())
- {
- *major = 4;
- *minor = 0;
- }
- else if (kernelAbove300())
- {
- *major = 3;
- *minor = 0;
- }
- else if (kernelAbove200())
- {
- *major = 2;
- *minor = 0;
- }
- else
- {
- // either 1.0 or > 5.x
- *major = 1;
- *minor = 0;
- }
-}
-
-static void frontend_switch_get_name(char *s, size_t len)
-{
- // TODO: Add Mariko at some point
- strlcpy(s, "Nintendo Switch", len);
-}
-
-frontend_ctx_driver_t frontend_ctx_switch =
- {
- frontend_switch_get_environment_settings,
- frontend_switch_init,
- frontend_switch_deinit,
- frontend_switch_exitspawn,
- NULL, /* process_args */
- frontend_switch_exec,
-#ifdef IS_SALAMANDER
- NULL,
-#else
- frontend_switch_set_fork,
-#endif
- frontend_switch_shutdown,
- frontend_switch_get_name,
- frontend_switch_get_os,
- frontend_switch_get_rating,
- NULL, /* load_content */
- frontend_switch_get_architecture,
- frontend_switch_get_powerstate,
- frontend_switch_parse_drive_list,
- frontend_switch_get_mem_total,
- frontend_switch_get_mem_used,
- NULL, /* install_signal_handler */
- NULL, /* get_signal_handler_state */
- NULL, /* set_signal_handler_state */
- NULL, /* destroy_signal_handler_state */
- NULL, /* attach_console */
- NULL, /* detach_console */
- NULL, /* watch_path_for_changes */
- NULL, /* check_for_path_changes */
- NULL, /* set_sustained_performance_mode */
- "switch",
-};
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+
+#include
+
+#ifdef HAVE_CONFIG_H
+#include "../../config.h"
+#endif
+
+#ifndef IS_SALAMANDER
+#include
+#endif
+
+#include "../frontend_driver.h"
+#include "../../verbosity.h"
+#include "../../defaults.h"
+#include "../../paths.h"
+#include "../../retroarch.h"
+#include "../../file_path_special.h"
+#include "../../audio/audio_driver.h"
+
+#ifndef IS_SALAMANDER
+#ifdef HAVE_MENU
+#include "../../menu/menu_driver.h"
+#endif
+#endif
+
+static enum frontend_fork switch_fork_mode = FRONTEND_FORK_NONE;
+static const char *elf_path_cst = "/switch/retroarch_switch.nro";
+
+static uint64_t frontend_switch_get_mem_used(void);
+
+// Splash
+static uint32_t *splashData = NULL;
+
+// switch_gfx.c protypes, we really need a header
+extern void gfx_slow_swizzling_blit(uint32_t *buffer, uint32_t *image, int w, int h, int tx, int ty, bool blend);
+
+static void get_first_valid_core(char *path_return)
+{
+ DIR *dir;
+ struct dirent *ent;
+ const char *extension = ".nro";
+
+ path_return[0] = '\0';
+
+ dir = opendir("/retroarch/cores");
+ if (dir != NULL)
+ {
+ while (ent = readdir(dir))
+ {
+ if (ent == NULL)
+ break;
+ if (strlen(ent->d_name) > strlen(extension) && !strcmp(ent->d_name + strlen(ent->d_name) - strlen(extension), extension))
+ {
+ strcpy(path_return, "/retroarch/cores");
+ strcat(path_return, "/");
+ strcat(path_return, ent->d_name);
+ break;
+ }
+ }
+ closedir(dir);
+ }
+}
+
+static void frontend_switch_get_environment_settings(int *argc, char *argv[], void *args, void *params_data)
+{
+ (void)args;
+
+#ifndef IS_SALAMANDER
+#if defined(HAVE_LOGGER)
+ logger_init();
+#elif defined(HAVE_FILE_LOGGER)
+ retro_main_log_file_init("/retroarch-log.txt");
+#endif
+#endif
+
+ fill_pathname_basedir(g_defaults.dirs[DEFAULT_DIR_PORT], "/retroarch/retroarch_switch.nro", sizeof(g_defaults.dirs[DEFAULT_DIR_PORT]));
+ RARCH_LOG("port dir: [%s]\n", g_defaults.dirs[DEFAULT_DIR_PORT]);
+
+ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], g_defaults.dirs[DEFAULT_DIR_PORT],
+ "downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
+
+ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], g_defaults.dirs[DEFAULT_DIR_PORT],
+ "media", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
+
+ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], g_defaults.dirs[DEFAULT_DIR_PORT],
+ "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
+
+ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], g_defaults.dirs[DEFAULT_DIR_CORE],
+ "info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
+
+ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], g_defaults.dirs[DEFAULT_DIR_CORE],
+ "savestates", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE]));
+
+ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], g_defaults.dirs[DEFAULT_DIR_CORE],
+ "savefiles", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM]));
+
+ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], g_defaults.dirs[DEFAULT_DIR_CORE],
+ "system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM]));
+
+ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], g_defaults.dirs[DEFAULT_DIR_CORE],
+ "playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
+
+ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], g_defaults.dirs[DEFAULT_DIR_PORT],
+ "config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG]));
+
+ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP], g_defaults.dirs[DEFAULT_DIR_PORT],
+ "config/remaps", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP]));
+
+ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], g_defaults.dirs[DEFAULT_DIR_PORT],
+ "filters", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP]));
+
+ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], g_defaults.dirs[DEFAULT_DIR_PORT],
+ "database/rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE]));
+
+ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CURSOR], g_defaults.dirs[DEFAULT_DIR_PORT],
+ "database/cursors", sizeof(g_defaults.dirs[DEFAULT_DIR_CURSOR]));
+
+ fill_pathname_join(g_defaults.path.config, g_defaults.dirs[DEFAULT_DIR_PORT],
+ file_path_str(FILE_PATH_MAIN_CONFIG), sizeof(g_defaults.path.config));
+}
+
+static void frontend_switch_deinit(void *data)
+{
+ (void)data;
+
+#if defined(HAVE_LIBNX) && defined(NXLINK) // Else freeze on exit
+ socketExit();
+#endif
+
+ // Splash
+ if (splashData)
+ {
+ free(splashData);
+ splashData = NULL;
+ }
+
+ gfxExit();
+}
+
+static void frontend_switch_exec(const char *path, bool should_load_game)
+{
+ char game_path[PATH_MAX];
+ const char *arg_data[3];
+ char error_string[200 + PATH_MAX];
+ int args = 0;
+ int error = 0;
+
+ game_path[0] = NULL;
+ arg_data[0] = NULL;
+
+ arg_data[args] = elf_path_cst;
+ arg_data[args + 1] = NULL;
+ args++;
+
+ RARCH_LOG("Attempt to load core: [%s].\n", path);
+#ifndef IS_SALAMANDER
+ if (should_load_game && !path_is_empty(RARCH_PATH_CONTENT))
+ {
+ strcpy(game_path, path_get(RARCH_PATH_CONTENT));
+ arg_data[args] = game_path;
+ arg_data[args + 1] = NULL;
+ args++;
+ RARCH_LOG("content path: [%s].\n", path_get(RARCH_PATH_CONTENT));
+ }
+#endif
+
+ if (path && path[0])
+ {
+#ifdef IS_SALAMANDER
+ struct stat sbuff;
+ bool file_exists;
+
+ file_exists = stat(path, &sbuff) == 0;
+ if (!file_exists)
+ {
+ char core_path[PATH_MAX];
+
+ /* find first valid core and load it if the target core doesnt exist */
+ get_first_valid_core(&core_path[0]);
+
+ if (core_path[0] == '\0')
+ {
+ /*errorInit(&error_dialog, ERROR_TEXT, CFG_LANGUAGE_EN);
+ errorText(&error_dialog, "There are no cores installed, install a core to continue.");
+ errorDisp(&error_dialog);*/
+ svcExitProcess();
+ }
+ }
+#endif
+ char *argBuffer = (char *)malloc(PATH_MAX);
+ if (should_load_game)
+ {
+ snprintf(argBuffer, PATH_MAX, "%s \"%s\"", path, game_path);
+ }
+ else
+ {
+ snprintf(argBuffer, PATH_MAX, "%s", path);
+ }
+
+ envSetNextLoad(path, argBuffer);
+ }
+}
+
+#ifndef IS_SALAMANDER
+static bool frontend_switch_set_fork(enum frontend_fork fork_mode)
+{
+ switch (fork_mode)
+ {
+ case FRONTEND_FORK_CORE:
+ RARCH_LOG("FRONTEND_FORK_CORE\n");
+ switch_fork_mode = fork_mode;
+ break;
+ case FRONTEND_FORK_CORE_WITH_ARGS:
+ RARCH_LOG("FRONTEND_FORK_CORE_WITH_ARGS\n");
+ switch_fork_mode = fork_mode;
+ break;
+ case FRONTEND_FORK_RESTART:
+ RARCH_LOG("FRONTEND_FORK_RESTART\n");
+ /* NOTE: We don't implement Salamander, so just turn
+ this into FRONTEND_FORK_CORE. */
+ switch_fork_mode = FRONTEND_FORK_CORE;
+ break;
+ case FRONTEND_FORK_NONE:
+ default:
+ return false;
+ }
+
+ return true;
+}
+#endif
+
+static void frontend_switch_exitspawn(char *s, size_t len)
+{
+ bool should_load_game = false;
+#ifndef IS_SALAMANDER
+ if (switch_fork_mode == FRONTEND_FORK_NONE)
+ return;
+
+ switch (switch_fork_mode)
+ {
+ case FRONTEND_FORK_CORE_WITH_ARGS:
+ should_load_game = true;
+ break;
+ default:
+ break;
+ }
+#endif
+ frontend_switch_exec(s, should_load_game);
+}
+
+static void frontend_switch_shutdown(bool unused)
+{
+ (void)unused;
+}
+
+void argb_to_rgba8(uint32_t *buff, uint32_t height, uint32_t width)
+{
+ // Convert
+ for (uint32_t h = 0; h < height; h++)
+ {
+ for (uint32_t w = 0; w < width; w++)
+ {
+ uint32_t offset = (h * width) + w;
+ uint32_t c = buff[offset];
+
+ uint32_t a = (uint32_t)((c & 0xff000000) >> 24);
+ uint32_t r = (uint32_t)((c & 0x00ff0000) >> 16);
+ uint32_t g = (uint32_t)((c & 0x0000ff00) >> 8);
+ uint32_t b = (uint32_t)(c & 0x000000ff);
+
+ buff[offset] = RGBA8(r, g, b, a);
+ }
+ }
+}
+
+void frontend_switch_showsplash()
+{
+ printf("[Splash] Showing splashScreen\n");
+
+ if (splashData)
+ {
+ uint32_t width, height;
+ width = height = 0;
+
+ uint32_t *frambuffer = (uint32_t *)gfxGetFramebuffer(&width, &height);
+
+ gfx_slow_swizzling_blit(frambuffer, splashData, width, height, 0, 0, false);
+
+ gfxFlushBuffers();
+ gfxSwapBuffers();
+ gfxWaitForVsync();
+ }
+}
+
+// From rpng_test.c
+bool rpng_load_image_argb(const char *path, uint32_t **data, unsigned *width, unsigned *height)
+{
+ int retval;
+ size_t file_len;
+ bool ret = true;
+ rpng_t *rpng = NULL;
+ void *ptr = NULL;
+
+ struct nbio_t *handle = (struct nbio_t *)nbio_open(path, NBIO_READ);
+
+ if (!handle)
+ goto end;
+
+ nbio_begin_read(handle);
+
+ while (!nbio_iterate(handle))
+ svcSleepThread(3);
+
+ ptr = nbio_get_ptr(handle, &file_len);
+
+ if (!ptr)
+ {
+ ret = false;
+ goto end;
+ }
+
+ rpng = rpng_alloc();
+
+ if (!rpng)
+ {
+ ret = false;
+ goto end;
+ }
+
+ if (!rpng_set_buf_ptr(rpng, (uint8_t *)ptr))
+ {
+ ret = false;
+ goto end;
+ }
+
+ if (!rpng_start(rpng))
+ {
+ ret = false;
+ goto end;
+ }
+
+ while (rpng_iterate_image(rpng))
+ svcSleepThread(3);
+
+ if (!rpng_is_valid(rpng))
+ {
+ ret = false;
+ goto end;
+ }
+
+ do
+ {
+ retval = rpng_process_image(rpng, (void **)data, file_len, width, height);
+ svcSleepThread(3);
+ } while (retval == IMAGE_PROCESS_NEXT);
+
+ if (retval == IMAGE_PROCESS_ERROR || retval == IMAGE_PROCESS_ERROR_END)
+ ret = false;
+
+end:
+ if (handle)
+ nbio_free(handle);
+
+ if (rpng)
+ rpng_free(rpng);
+
+ rpng = NULL;
+
+ if (!ret)
+ free(*data);
+
+ return ret;
+}
+
+int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+ svcSleepThread(rqtp->tv_nsec + (rqtp->tv_sec * 1000000000));
+ return 0;
+}
+
+long sysconf(int name)
+{
+ switch (name)
+ {
+ case 8:
+ return 0x1000;
+ }
+ return -1;
+}
+
+ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize)
+{
+ return -1;
+}
+
+// Taken from glibc
+char *realpath(const char *name, char *resolved)
+{
+ char *rpath, *dest, *extra_buf = NULL;
+ const char *start, *end, *rpath_limit;
+ long int path_max;
+ int num_links = 0;
+
+ if (name == NULL)
+ {
+ /* As per Single Unix Specification V2 we must return an error if
+ either parameter is a null pointer. We extend this to allow
+ the RESOLVED parameter to be NULL in case the we are expected to
+ allocate the room for the return value. */
+ return NULL;
+ }
+
+ if (name[0] == '\0')
+ {
+ /* As per Single Unix Specification V2 we must return an error if
+ the name argument points to an empty string. */
+ return NULL;
+ }
+
+#ifdef PATH_MAX
+ path_max = PATH_MAX;
+#else
+ path_max = pathconf(name, _PC_PATH_MAX);
+ if (path_max <= 0)
+ path_max = 1024;
+#endif
+
+ if (resolved == NULL)
+ {
+ rpath = malloc(path_max);
+ if (rpath == NULL)
+ return NULL;
+ }
+ else
+ rpath = resolved;
+ rpath_limit = rpath + path_max;
+
+ if (name[0] != '/')
+ {
+ if (!getcwd(rpath, path_max))
+ {
+ rpath[0] = '\0';
+ goto error;
+ }
+ dest = memchr(rpath, '\0', path_max);
+ }
+ else
+ {
+ rpath[0] = '/';
+ dest = rpath + 1;
+ }
+
+ for (start = end = name; *start; start = end)
+ {
+ int n;
+
+ /* Skip sequence of multiple path-separators. */
+ while (*start == '/')
+ ++start;
+
+ /* Find end of path component. */
+ for (end = start; *end && *end != '/'; ++end)
+ /* Nothing. */;
+
+ if (end - start == 0)
+ break;
+ else if (end - start == 1 && start[0] == '.')
+ /* nothing */;
+ else if (end - start == 2 && start[0] == '.' && start[1] == '.')
+ {
+ /* Back up to previous component, ignore if at root already. */
+ if (dest > rpath + 1)
+ while ((--dest)[-1] != '/')
+ ;
+ }
+ else
+ {
+ size_t new_size;
+
+ if (dest[-1] != '/')
+ *dest++ = '/';
+
+ if (dest + (end - start) >= rpath_limit)
+ {
+ ptrdiff_t dest_offset = dest - rpath;
+ char *new_rpath;
+
+ if (resolved)
+ {
+ if (dest > rpath + 1)
+ dest--;
+ *dest = '\0';
+ goto error;
+ }
+ new_size = rpath_limit - rpath;
+ if (end - start + 1 > path_max)
+ new_size += end - start + 1;
+ else
+ new_size += path_max;
+ new_rpath = (char *)realloc(rpath, new_size);
+ if (new_rpath == NULL)
+ goto error;
+ rpath = new_rpath;
+ rpath_limit = rpath + new_size;
+
+ dest = rpath + dest_offset;
+ }
+
+ dest = memcpy(dest, start, end - start);
+ *dest = '\0';
+ }
+ }
+ if (dest > rpath + 1 && dest[-1] == '/')
+ --dest;
+ *dest = '\0';
+
+ return rpath;
+
+error:
+ if (resolved == NULL)
+ free(rpath);
+ return NULL;
+}
+
+// runloop_get_system_info isnt initialized that early..
+extern void retro_get_system_info(struct retro_system_info *info);
+
+static void frontend_switch_init(void *data)
+{
+ (void)data;
+
+ // Init Resolution before initDefault
+ gfxInitResolution(1280, 720);
+
+ gfxInitDefault();
+ gfxSetMode(GfxMode_TiledDouble);
+
+ gfxConfigureTransform(0);
+
+#if defined(HAVE_LIBNX) && defined(NXLINK)
+ socketInitializeDefault();
+ nxlinkStdio();
+#ifndef IS_SALAMANDER
+ verbosity_enable();
+#endif
+#endif
+
+ rarch_system_info_t *sys_info = runloop_get_system_info();
+ retro_get_system_info(sys_info);
+
+ const char *core_name = NULL;
+
+ printf("[Video]: Video initialized\n");
+
+ uint32_t width, height;
+ width = height = 0;
+
+ // Load splash
+ if (!splashData)
+ {
+ if (sys_info)
+ {
+ core_name = sys_info->info.library_name;
+ char *full_core_splash_path = (char *)malloc(PATH_MAX);
+ snprintf(full_core_splash_path, PATH_MAX, "/retroarch/rgui/splash/%s.png", core_name);
+
+ rpng_load_image_argb((const char *)full_core_splash_path, &splashData, &width, &height);
+ if (splashData)
+ {
+ argb_to_rgba8(splashData, height, width);
+ frontend_switch_showsplash();
+ }
+ else
+ {
+ rpng_load_image_argb("/retroarch/rgui/splash/RetroArch.png", &splashData, &width, &height);
+ if (splashData)
+ {
+ argb_to_rgba8(splashData, height, width);
+ frontend_switch_showsplash();
+ }
+ }
+
+ free(full_core_splash_path);
+ }
+ else
+ {
+ rpng_load_image_argb("/retroarch/rgui/splash/RetroArch.png", &splashData, &width, &height);
+ if (splashData)
+ {
+ argb_to_rgba8(splashData, height, width);
+ frontend_switch_showsplash();
+ }
+ }
+ }
+ else
+ {
+ frontend_switch_showsplash();
+ }
+}
+
+static int frontend_switch_get_rating(void)
+{
+ return 1000;
+}
+
+enum frontend_architecture frontend_switch_get_architecture(void)
+{
+ return FRONTEND_ARCH_ARMV8;
+}
+
+static int frontend_switch_parse_drive_list(void *data, bool load_content)
+{
+#ifndef IS_SALAMANDER
+ file_list_t *list = (file_list_t *)data;
+ enum msg_hash_enums enum_idx = load_content ? MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR : MSG_UNKNOWN;
+
+ if (!list)
+ return -1;
+
+ menu_entries_append_enum(list, "/", msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
+ enum_idx,
+ FILE_TYPE_DIRECTORY, 0, 0);
+#endif
+
+ return 0;
+}
+
+static uint64_t frontend_switch_get_mem_total(void)
+{
+ uint64_t memoryTotal = 0;
+ svcGetInfo(&memoryTotal, 6, CUR_PROCESS_HANDLE, 0); // avaiable
+ memoryTotal += frontend_switch_get_mem_used();
+
+ return memoryTotal;
+}
+
+static uint64_t frontend_switch_get_mem_used(void)
+{
+ uint64_t memoryUsed = 0;
+ svcGetInfo(&memoryUsed, 7, CUR_PROCESS_HANDLE, 0); // used
+
+ return memoryUsed;
+}
+
+static enum frontend_powerstate frontend_switch_get_powerstate(int *seconds, int *percent)
+{
+ // This is fine monkaS
+ return FRONTEND_POWERSTATE_CHARGED;
+}
+
+static void frontend_switch_get_os(char *s, size_t len, int *major, int *minor)
+{
+ strlcpy(s, "Horizon OS", len);
+
+ // There is pretty sure a better way, but this will do just fine
+ if (kernelAbove500())
+ {
+ *major = 5;
+ *minor = 0;
+ }
+ else if (kernelAbove400())
+ {
+ *major = 4;
+ *minor = 0;
+ }
+ else if (kernelAbove300())
+ {
+ *major = 3;
+ *minor = 0;
+ }
+ else if (kernelAbove200())
+ {
+ *major = 2;
+ *minor = 0;
+ }
+ else
+ {
+ // either 1.0 or > 5.x
+ *major = 1;
+ *minor = 0;
+ }
+}
+
+static void frontend_switch_get_name(char *s, size_t len)
+{
+ // TODO: Add Mariko at some point
+ strlcpy(s, "Nintendo Switch", len);
+}
+
+frontend_ctx_driver_t frontend_ctx_switch =
+ {
+ frontend_switch_get_environment_settings,
+ frontend_switch_init,
+ frontend_switch_deinit,
+ frontend_switch_exitspawn,
+ NULL, /* process_args */
+ frontend_switch_exec,
+#ifdef IS_SALAMANDER
+ NULL,
+#else
+ frontend_switch_set_fork,
+#endif
+ frontend_switch_shutdown,
+ frontend_switch_get_name,
+ frontend_switch_get_os,
+ frontend_switch_get_rating,
+ NULL, /* load_content */
+ frontend_switch_get_architecture,
+ frontend_switch_get_powerstate,
+ frontend_switch_parse_drive_list,
+ frontend_switch_get_mem_total,
+ frontend_switch_get_mem_used,
+ NULL, /* install_signal_handler */
+ NULL, /* get_signal_handler_state */
+ NULL, /* set_signal_handler_state */
+ NULL, /* destroy_signal_handler_state */
+ NULL, /* attach_console */
+ NULL, /* detach_console */
+ NULL, /* watch_path_for_changes */
+ NULL, /* check_for_path_changes */
+ NULL, /* set_sustained_performance_mode */
+ "switch",
+};
diff --git a/gfx/common/switch_common.h b/gfx/common/switch_common.h
index d3858cb975..205f8ab68d 100644
--- a/gfx/common/switch_common.h
+++ b/gfx/common/switch_common.h
@@ -1,59 +1,59 @@
-#ifndef SWITCH_COMMON_H__
-#define SWITCH_COMMON_H__
-
-#include
-#include
-
-typedef struct
-{
- bool vsync;
- bool rgb32;
- bool smooth; // bilinear
- unsigned width, height;
- unsigned rotation;
- struct video_viewport vp;
- struct texture_image *overlay;
- bool overlay_enabled;
- bool in_menu;
- struct
- {
- bool enable;
- bool fullscreen;
-
- uint32_t *pixels;
-
- uint32_t width;
- uint32_t height;
-
- unsigned tgtw;
- unsigned tgth;
-
- struct scaler_ctx scaler;
- } menu_texture;
-
- struct
- {
- uint32_t width;
- uint32_t height;
- uint32_t x_offset;
- } hw_scale;
-
- uint32_t image[1280 * 720];
- uint32_t tmp_image[1280 * 720];
- u32 cnt;
- struct scaler_ctx scaler;
- uint32_t last_width;
- uint32_t last_height;
- bool keep_aspect;
- bool should_resize;
- bool need_clear;
- bool is_threaded;
-
- bool o_size;
- uint32_t o_height;
- uint32_t o_width;
-} switch_video_t;
-
-void gfx_slow_swizzling_blit(uint32_t *buffer, uint32_t *image, int w, int h, int tx, int ty, bool blend);
-
-#endif
+#ifndef SWITCH_COMMON_H__
+#define SWITCH_COMMON_H__
+
+#include
+#include
+
+typedef struct
+{
+ bool vsync;
+ bool rgb32;
+ bool smooth; // bilinear
+ unsigned width, height;
+ unsigned rotation;
+ struct video_viewport vp;
+ struct texture_image *overlay;
+ bool overlay_enabled;
+ bool in_menu;
+ struct
+ {
+ bool enable;
+ bool fullscreen;
+
+ uint32_t *pixels;
+
+ uint32_t width;
+ uint32_t height;
+
+ unsigned tgtw;
+ unsigned tgth;
+
+ struct scaler_ctx scaler;
+ } menu_texture;
+
+ struct
+ {
+ uint32_t width;
+ uint32_t height;
+ uint32_t x_offset;
+ } hw_scale;
+
+ uint32_t image[1280 * 720];
+ uint32_t tmp_image[1280 * 720];
+ u32 cnt;
+ struct scaler_ctx scaler;
+ uint32_t last_width;
+ uint32_t last_height;
+ bool keep_aspect;
+ bool should_resize;
+ bool need_clear;
+ bool is_threaded;
+
+ bool o_size;
+ uint32_t o_height;
+ uint32_t o_width;
+} switch_video_t;
+
+void gfx_slow_swizzling_blit(uint32_t *buffer, uint32_t *image, int w, int h, int tx, int ty, bool blend);
+
+#endif
diff --git a/gfx/drivers/switch_nx_gfx.c b/gfx/drivers/switch_nx_gfx.c
index 3674852544..f207db442f 100644
--- a/gfx/drivers/switch_nx_gfx.c
+++ b/gfx/drivers/switch_nx_gfx.c
@@ -1,772 +1,772 @@
-/* RetroArch - A frontend for libretro.
- * Copyright (C) 2018 - misson2000
- * Copyright (C) 2018 - m4xw
- *
- * 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
-
-#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"
-
-#include "../common/switch_common.h"
-
-#ifndef HAVE_THREADS
-#include "../../tasks/tasks_internal.h"
-#endif
-
-#ifdef HAVE_NXRGUI
-extern uint32_t *nx_backgroundImage;
-// Temp Overlay // KILL IT WITH FIRE
-extern uint32_t *tmp_overlay;
-#endif
-
-// (C) libtransistor
-static int pdep(uint32_t mask, uint32_t value)
-{
- uint32_t out = 0;
- for (int shift = 0; shift < 32; shift++)
- {
- uint32_t bit = 1u << shift;
- if (mask & bit)
- {
- if (value & 1)
- out |= bit;
- value >>= 1;
- }
- }
- return out;
-}
-
-static uint32_t swizzle_x(uint32_t v) { return pdep(~0x7B4u, v); }
-static uint32_t swizzle_y(uint32_t v) { return pdep(0x7B4, v); }
-
-void gfx_slow_swizzling_blit(uint32_t *buffer, uint32_t *image, int w, int h, int tx, int ty, bool blend)
-{
- uint32_t *dest = buffer;
- uint32_t *src = image;
- int x0 = tx;
- int y0 = ty;
- int x1 = x0 + w;
- int y1 = y0 + h;
- const uint32_t tile_height = 128;
- const uint32_t padded_width = 128 * 10;
-
- // we're doing this in pixels - should just shift the swizzles instead
- uint32_t offs_x0 = swizzle_x(x0);
- uint32_t offs_y = swizzle_y(y0);
- uint32_t x_mask = swizzle_x(~0u);
- uint32_t y_mask = swizzle_y(~0u);
- uint32_t incr_y = swizzle_x(padded_width);
-
- // step offs_x0 to the right row of tiles
- offs_x0 += incr_y * (y0 / tile_height);
-
- uint32_t x, y;
- for (y = y0; y < y1; y++)
- {
- uint32_t *dest_line = dest + offs_y;
- uint32_t offs_x = offs_x0;
-
- for (x = x0; x < x1; x++)
- {
- uint32_t pixel = *src++;
- if (blend) // supercheap masking
- {
- uint32_t dst = dest_line[offs_x];
- uint8_t src_a = ((pixel & 0xFF000000) >> 24);
-
- if (src_a > 0)
- pixel &= 0x00FFFFFF;
- else
- pixel = dst;
- }
-
- dest_line[offs_x] = pixel;
-
- offs_x = (offs_x - x_mask) & x_mask;
- }
-
- offs_y = (offs_y - y_mask) & y_mask;
- if (!offs_y)
- offs_x0 += incr_y; // wrap into next tile row
- }
-}
-
-// needed to clear surface completely as hw scaling doesn't always scale to full resoution perflectly
-static void clear_screen(switch_video_t *sw)
-{
- gfxConfigureResolution(sw->vp.full_width, sw->vp.full_height);
-
- uint32_t *out_buffer = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
-
- memset(out_buffer, 0, gfxGetFramebufferSize());
-
- gfxFlushBuffers();
- gfxSwapBuffers();
- gfxWaitForVsync();
-}
-
-static void *switch_init(const video_info_t *video,
- const input_driver_t **input, void **input_data)
-{
- void *switchinput = NULL;
- switch_video_t *sw = (switch_video_t *)calloc(1, sizeof(*sw));
- if (!sw)
- return NULL;
-
- printf("loading switch gfx driver, width: %d, height: %d threaded: %d smooth %d\n", video->width, video->height, video->is_threaded, video->smooth);
- sw->vp.x = 0;
- sw->vp.y = 0;
- sw->vp.width = sw->o_width = video->width;
- sw->vp.height = sw->o_height = video->height;
- sw->overlay_enabled = false;
- sw->overlay = NULL;
- sw->in_menu = false;
-
- sw->vp.full_width = 1280;
- sw->vp.full_height = 720;
-
- // Sanity check
- sw->vp.width = MIN(sw->vp.width, sw->vp.full_width);
- sw->vp.height = MIN(sw->vp.height, sw->vp.full_height);
-
- sw->vsync = video->vsync;
- sw->rgb32 = video->rgb32;
- sw->keep_aspect = true;
- sw->should_resize = true;
- sw->o_size = true;
- sw->is_threaded = video->is_threaded;
- sw->smooth = video->smooth;
- sw->menu_texture.enable = false;
-
- // Autoselect driver
- if (input && input_data)
- {
- settings_t *settings = config_get_ptr();
- switchinput = input_switch.init(settings->arrays.input_joypad_driver);
- *input = switchinput ? &input_switch : NULL;
- *input_data = switchinput;
- }
-
- font_driver_init_osd(sw, false,
- video->is_threaded,
- FONT_DRIVER_RENDER_SWITCH);
-
- clear_screen(sw);
-
- return sw;
-}
-
-static void switch_update_viewport(switch_video_t *sw,
- video_frame_info_t *video_info)
-{
- settings_t *settings = config_get_ptr();
- int x = 0;
- int y = 0;
- float desired_aspect = 0.0f;
- float width = sw->vp.full_width;
- float height = sw->vp.full_height;
-
- if (sw->o_size)
- {
- width = sw->o_width;
- height = sw->o_height;
- sw->vp.x = (int)(((float)sw->vp.full_width - width)) / 2;
- sw->vp.y = (int)(((float)sw->vp.full_height - height)) / 2;
-
- sw->vp.width = width;
- sw->vp.height = height;
-
- return;
- }
-
- desired_aspect = video_driver_get_aspect_ratio();
-
- /* We crash if >1.0f */
- printf("[Video] Aspect: %f\n", desired_aspect);
- /*if (desired_aspect > 1.8f)
- desired_aspect = 1.7778f;
-
- if (desired_aspect < 1.2f && desired_aspect != 0.0f)
- desired_aspect = 1.0f;*/
-
- if (settings->bools.video_scale_integer)
- {
- video_viewport_get_scaled_integer(&sw->vp, sw->vp.full_width, sw->vp.full_height, desired_aspect, sw->keep_aspect);
- }
- else if (sw->keep_aspect)
- {
-#if defined(HAVE_MENU)
- if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
- {
- sw->vp.x = sw->vp.y = 0;
- sw->vp.width = width;
- sw->vp.height = height;
- }
- else
-#endif
- {
- float delta;
- float device_aspect = ((float)sw->vp.full_width) / sw->vp.full_height;
-
- if (fabsf(device_aspect - desired_aspect) < 0.0001f)
- {
- /*
- * If the aspect ratios of screen and desired aspect
- * ratio are sufficiently equal (floating point stuff),
- * assume they are actually equal.
- */
- }
- else if (device_aspect > desired_aspect)
- {
- delta = (desired_aspect / device_aspect - 1.0f) / 2.0f + 0.5f;
- x = (int)roundf(width * (0.5f - delta));
- width = (unsigned)roundf(2.0f * width * delta);
- }
- else
- {
- delta = (device_aspect / desired_aspect - 1.0f) / 2.0f + 0.5f;
- y = (int)roundf(height * (0.5f - delta));
- height = (unsigned)roundf(2.0f * height * delta);
- }
- }
-
- sw->vp.x = x;
- sw->vp.y = y;
-
- sw->vp.width = width;
- sw->vp.height = height;
- }
- else
- {
- sw->vp.x = sw->vp.y = 0;
- sw->vp.width = width;
- sw->vp.height = height;
- }
-}
-
-static void switch_set_aspect_ratio(void *data, unsigned aspect_ratio_idx)
-{
- switch_video_t *sw = (switch_video_t *)data;
-
- if (!sw)
- return;
-
- sw->keep_aspect = true;
- sw->o_size = false;
-
- settings_t *settings = config_get_ptr();
-
- switch (aspect_ratio_idx)
- {
- case ASPECT_RATIO_SQUARE:
- video_driver_set_viewport_square_pixel();
- break;
-
- case ASPECT_RATIO_CORE:
- video_driver_set_viewport_core();
- sw->o_size = true;
- sw->keep_aspect = false;
- break;
-
- case ASPECT_RATIO_CONFIG:
- video_driver_set_viewport_config();
- break;
-
- case ASPECT_RATIO_CUSTOM:
- if (settings->bools.video_scale_integer)
- {
- video_driver_set_viewport_core();
- sw->o_size = true;
- sw->keep_aspect = false;
- }
- break;
-
- default:
- break;
- }
-
- video_driver_set_aspect_ratio_value(aspectratio_lut[aspect_ratio_idx].value);
-
- sw->should_resize = true;
-}
-
-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;
- uint32_t *out_buffer = NULL;
- bool ffwd_mode = video_info->input_driver_nonblock_state;
-
- if (!frame)
- return true;
-
- if (ffwd_mode && !sw->is_threaded)
- {
- // render every 4th frame when in ffwd mode and not threaded
- if ((frame_count % 4) != 0)
- return true;
- }
-
- if (sw->should_resize || width != sw->last_width || height != sw->last_height)
- {
- printf("[Video] Requesting new size: width %i height %i\n", width, height);
- printf("[Video] fw: %i fh: %i w: %i h: %i x: %i y: %i\n", sw->vp.full_width, sw->vp.full_height, sw->vp.width, sw->vp.height, sw->vp.x, sw->vp.y);
- switch_update_viewport(sw, video_info);
- printf("[Video] fw: %i fh: %i w: %i h: %i x: %i y: %i\n", sw->vp.full_width, sw->vp.full_height, sw->vp.width, sw->vp.height, sw->vp.x, sw->vp.y);
-
- // Sanity check
- sw->vp.width = MIN(sw->vp.width, sw->vp.full_width);
- sw->vp.height = MIN(sw->vp.height, sw->vp.full_height);
-
- scaler_ctx_gen_reset(&sw->scaler);
-
- sw->scaler.in_width = width;
- sw->scaler.in_height = height;
- sw->scaler.in_stride = pitch;
- sw->scaler.in_fmt = sw->rgb32 ? SCALER_FMT_ARGB8888 : SCALER_FMT_RGB565;
-
- if (!sw->smooth)
- {
- sw->scaler.out_width = sw->vp.width;
- sw->scaler.out_height = sw->vp.height;
- sw->scaler.out_stride = sw->vp.full_width * sizeof(uint32_t);
- }
- else
- {
- sw->scaler.out_width = width;
- sw->scaler.out_height = height;
- sw->scaler.out_stride = width * sizeof(uint32_t);
-
- float screen_ratio = (float)sw->vp.full_width / sw->vp.full_height;
- float tgt_ratio = (float)sw->vp.width / sw->vp.height;
-
- sw->hw_scale.width = ceil(screen_ratio / tgt_ratio * sw->scaler.out_width);
- sw->hw_scale.height = sw->scaler.out_height;
- sw->hw_scale.x_offset = ceil((sw->hw_scale.width - sw->scaler.out_width) / 2.0);
- if (!video_info->menu_is_alive)
- {
- clear_screen(sw);
- gfxConfigureResolution(sw->hw_scale.width, sw->hw_scale.height);
- }
- }
- sw->scaler.out_fmt = SCALER_FMT_ABGR8888;
-
- sw->scaler.scaler_type = SCALER_TYPE_POINT;
-
- if (!scaler_ctx_gen_filter(&sw->scaler))
- {
- printf("failed to generate scaler for main image\n");
- return false;
- }
-
- sw->last_width = width;
- sw->last_height = height;
-
- sw->should_resize = false;
- }
-
- out_buffer = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
-
- if (sw->in_menu && !video_info->menu_is_alive && sw->smooth)
- {
- memset(out_buffer, 0, sw->vp.full_width * sw->vp.full_height * 4);
- gfxConfigureResolution(sw->hw_scale.width, sw->hw_scale.height);
- }
- sw->in_menu = video_info->menu_is_alive;
-
- if (sw->menu_texture.enable)
- {
- menu_driver_frame(video_info);
-
- if (sw->menu_texture.pixels)
- {
-#ifdef HAVE_NXRGUI
- gfx_slow_swizzling_blit(out_buffer, nx_backgroundImage, sw->vp.full_width, sw->vp.full_height, 0, 0, false);
-#else
- memset(out_buffer, 0, gfxGetFramebufferSize());
-#endif
- scaler_ctx_scale(&sw->menu_texture.scaler, sw->tmp_image + ((sw->vp.full_height - sw->menu_texture.tgth) / 2) * sw->vp.full_width + ((sw->vp.full_width - sw->menu_texture.tgtw) / 2), sw->menu_texture.pixels);
- gfx_slow_swizzling_blit(out_buffer, sw->tmp_image, sw->vp.full_width, sw->vp.full_height, 0, 0, true);
- }
- }
- else if (sw->smooth) // bilinear
- {
- struct scaler_ctx *ctx = &sw->scaler;
- scaler_ctx_scale_direct(ctx, sw->image, frame);
- int w = sw->scaler.out_width;
- int h = sw->scaler.out_height;
- for (int y = 0; y < h; y++)
- for (int x = 0; x < w; x++)
- out_buffer[gfxGetFramebufferDisplayOffset(x + sw->hw_scale.x_offset, y)] = sw->image[y * w + x];
- }
- else
- {
- struct scaler_ctx *ctx = &sw->scaler;
- scaler_ctx_scale(ctx, sw->image + (sw->vp.y * sw->vp.full_width) + sw->vp.x, frame);
- gfx_slow_swizzling_blit(out_buffer, sw->image, sw->vp.full_width, sw->vp.full_height, 0, 0, false);
-#ifdef HAVE_NXRGUI
- if (tmp_overlay)
- {
- gfx_slow_swizzling_blit(out_buffer, tmp_overlay, sw->vp.full_width, sw->vp.full_height, 0, 0, true);
- }
-#endif
- }
-
- if (video_info->statistics_show && !sw->smooth)
- {
- struct font_params *osd_params = (struct font_params *)&video_info->osd_stat_params;
-
- if (osd_params)
- font_driver_render_msg(video_info, NULL, video_info->stat_text,
- (const struct font_params *)&video_info->osd_stat_params);
- }
-
- if (msg)
- font_driver_render_msg(video_info, NULL, msg, NULL);
-
- gfxFlushBuffers();
- gfxSwapBuffers();
- if (sw->vsync || video_info->menu_is_alive)
- gfxWaitForVsync();
-
- 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;
- if (sw->menu_texture.pixels)
- free(sw->menu_texture.pixels);
-
- free(sw);
-}
-
-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;
- if (!sw)
- return;
- 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_set_texture_frame(
- void *data, const void *frame, bool rgb32,
- unsigned width, unsigned height, float alpha)
-{
- switch_video_t *sw = data;
- size_t sz = width * height * (rgb32 ? 4 : 2);
-
- if (!sw->menu_texture.pixels ||
- sw->menu_texture.width != width ||
- sw->menu_texture.height != height)
- {
- if (sw->menu_texture.pixels)
- realloc(sw->menu_texture.pixels, sz);
- else
- sw->menu_texture.pixels = malloc(sz);
-
- if (!sw->menu_texture.pixels)
- {
- printf("failed to allocate buffer for menu texture\n");
- return;
- }
-
- int xsf = 1280 / width;
- int ysf = 720 / height;
- int sf = xsf;
-
- if (ysf < sf)
- sf = ysf;
-
- sw->menu_texture.width = width;
- sw->menu_texture.height = height;
- sw->menu_texture.tgtw = width * sf;
- sw->menu_texture.tgth = height * sf;
-
- struct scaler_ctx *sctx = &sw->menu_texture.scaler;
- scaler_ctx_gen_reset(sctx);
-
- sctx->in_width = width;
- sctx->in_height = height;
- sctx->in_stride = width * (rgb32 ? 4 : 2);
- sctx->in_fmt = rgb32 ? SCALER_FMT_ARGB8888 : SCALER_FMT_RGB565;
- sctx->out_width = sw->menu_texture.tgtw;
- sctx->out_height = sw->menu_texture.tgth;
- sctx->out_stride = 1280 * 4;
- sctx->out_fmt = SCALER_FMT_ABGR8888;
-
- sctx->scaler_type = SCALER_TYPE_POINT;
-
- if (!scaler_ctx_gen_filter(sctx))
- {
- printf("failed to generate scaler for menu texture\n");
- return;
- }
- }
-
- memcpy(sw->menu_texture.pixels, frame, sz);
-}
-
-static void switch_apply_state_changes(void *data)
-{
- (void)data;
-}
-
-static void switch_set_texture_enable(void *data, bool enable, bool full_screen)
-{
- switch_video_t *sw = data;
-
- if (!sw->menu_texture.enable && enable)
- gfxConfigureResolution(sw->vp.full_width, sw->vp.full_height);
- else if (!enable && sw->menu_texture.enable && sw->smooth)
- {
- clear_screen(sw);
- gfxConfigureResolution(sw->hw_scale.width, sw->hw_scale.height);
- }
-
- sw->menu_texture.enable = enable;
- sw->menu_texture.fullscreen = full_screen;
-}
-
-static void switch_set_osd_msg(void *data,
- video_frame_info_t *video_info,
- const char *msg,
- const void *params, void *font)
-{
- switch_video_t *sw = (switch_video_t *)data;
-
- if (sw)
- font_driver_render_msg(video_info, font, msg, params);
-}
-
-#ifdef HAVE_OVERLAY
-static void switch_overlay_enable(void *data, bool state)
-{
- printf("[Video] Enabled Overlay\n");
-
- switch_video_t *swa = (switch_video_t *)data;
-
- if (!swa)
- return;
-
- swa->overlay_enabled = state;
-}
-
-static bool switch_overlay_load(void *data,
- const void *image_data, unsigned num_images)
-{
- switch_video_t *swa = (switch_video_t *)data;
-
- struct texture_image *images = (struct texture_image *)image_data;
-
- if (!swa)
- return false;
-
- swa->overlay = images;
- swa->overlay_enabled = true;
-
- return true;
-}
-
-static void switch_overlay_tex_geom(void *data,
- unsigned idx, float x, float y, float w, float h)
-{
- switch_video_t *swa = (switch_video_t *)data;
-
- if (!swa)
- return;
-}
-
-static void switch_overlay_vertex_geom(void *data,
- unsigned idx, float x, float y, float w, float h)
-{
- switch_video_t *swa = (switch_video_t *)data;
-
- if (!swa)
- return;
-}
-
-static void switch_overlay_full_screen(void *data, bool enable)
-{
- (void)data;
- (void)enable;
-}
-
-static void switch_overlay_set_alpha(void *data, unsigned idx, float mod)
-{
- (void)data;
- (void)idx;
- (void)mod;
-}
-
-static const video_overlay_interface_t switch_overlay = {
- switch_overlay_enable,
- switch_overlay_load,
- switch_overlay_tex_geom,
- switch_overlay_vertex_geom,
- switch_overlay_full_screen,
- switch_overlay_set_alpha,
-};
-
-void switch_overlay_interface(void *data, const video_overlay_interface_t **iface)
-{
- switch_video_t *swa = (switch_video_t *)data;
- if (!swa)
- return;
- *iface = &switch_overlay;
-}
-
-#endif
-
-static const video_poke_interface_t switch_poke_interface = {
- NULL, /* get_flags */
- NULL, /* set_coords */
- NULL, /* set_mvp */
- NULL, /* load_texture */
- NULL, /* unload_texture */
- NULL, /* set_video_mode */
- NULL, /* 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 */
- switch_set_aspect_ratio, /* set_aspect_ratio */
- switch_apply_state_changes, /* apply_state_changes */
- switch_set_texture_frame,
- switch_set_texture_enable,
- switch_set_osd_msg,
- NULL, /* show_mouse */
- NULL, /* grab_mouse_toggle */
- NULL, /* get_current_shader */
- NULL, /* get_current_software_framebuffer */
- NULL, /* get_hw_render_interface */
-};
-
-static void switch_get_poke_interface(void *data,
- const video_poke_interface_t **iface)
-{
- (void)data;
- *iface = &switch_poke_interface;
-}
-
-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
- switch_overlay_interface, /* switch_overlay_interface */
-#endif
- switch_get_poke_interface,
-};
-
-/* vim: set ts=6 sw=6 sts=6: */
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2018 - misson2000
+ * Copyright (C) 2018 - m4xw
+ *
+ * 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
+
+#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"
+
+#include "../common/switch_common.h"
+
+#ifndef HAVE_THREADS
+#include "../../tasks/tasks_internal.h"
+#endif
+
+#ifdef HAVE_NXRGUI
+extern uint32_t *nx_backgroundImage;
+// Temp Overlay // KILL IT WITH FIRE
+extern uint32_t *tmp_overlay;
+#endif
+
+// (C) libtransistor
+static int pdep(uint32_t mask, uint32_t value)
+{
+ uint32_t out = 0;
+ for (int shift = 0; shift < 32; shift++)
+ {
+ uint32_t bit = 1u << shift;
+ if (mask & bit)
+ {
+ if (value & 1)
+ out |= bit;
+ value >>= 1;
+ }
+ }
+ return out;
+}
+
+static uint32_t swizzle_x(uint32_t v) { return pdep(~0x7B4u, v); }
+static uint32_t swizzle_y(uint32_t v) { return pdep(0x7B4, v); }
+
+void gfx_slow_swizzling_blit(uint32_t *buffer, uint32_t *image, int w, int h, int tx, int ty, bool blend)
+{
+ uint32_t *dest = buffer;
+ uint32_t *src = image;
+ int x0 = tx;
+ int y0 = ty;
+ int x1 = x0 + w;
+ int y1 = y0 + h;
+ const uint32_t tile_height = 128;
+ const uint32_t padded_width = 128 * 10;
+
+ // we're doing this in pixels - should just shift the swizzles instead
+ uint32_t offs_x0 = swizzle_x(x0);
+ uint32_t offs_y = swizzle_y(y0);
+ uint32_t x_mask = swizzle_x(~0u);
+ uint32_t y_mask = swizzle_y(~0u);
+ uint32_t incr_y = swizzle_x(padded_width);
+
+ // step offs_x0 to the right row of tiles
+ offs_x0 += incr_y * (y0 / tile_height);
+
+ uint32_t x, y;
+ for (y = y0; y < y1; y++)
+ {
+ uint32_t *dest_line = dest + offs_y;
+ uint32_t offs_x = offs_x0;
+
+ for (x = x0; x < x1; x++)
+ {
+ uint32_t pixel = *src++;
+ if (blend) // supercheap masking
+ {
+ uint32_t dst = dest_line[offs_x];
+ uint8_t src_a = ((pixel & 0xFF000000) >> 24);
+
+ if (src_a > 0)
+ pixel &= 0x00FFFFFF;
+ else
+ pixel = dst;
+ }
+
+ dest_line[offs_x] = pixel;
+
+ offs_x = (offs_x - x_mask) & x_mask;
+ }
+
+ offs_y = (offs_y - y_mask) & y_mask;
+ if (!offs_y)
+ offs_x0 += incr_y; // wrap into next tile row
+ }
+}
+
+// needed to clear surface completely as hw scaling doesn't always scale to full resoution perflectly
+static void clear_screen(switch_video_t *sw)
+{
+ gfxConfigureResolution(sw->vp.full_width, sw->vp.full_height);
+
+ uint32_t *out_buffer = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
+
+ memset(out_buffer, 0, gfxGetFramebufferSize());
+
+ gfxFlushBuffers();
+ gfxSwapBuffers();
+ gfxWaitForVsync();
+}
+
+static void *switch_init(const video_info_t *video,
+ const input_driver_t **input, void **input_data)
+{
+ void *switchinput = NULL;
+ switch_video_t *sw = (switch_video_t *)calloc(1, sizeof(*sw));
+ if (!sw)
+ return NULL;
+
+ printf("loading switch gfx driver, width: %d, height: %d threaded: %d smooth %d\n", video->width, video->height, video->is_threaded, video->smooth);
+ sw->vp.x = 0;
+ sw->vp.y = 0;
+ sw->vp.width = sw->o_width = video->width;
+ sw->vp.height = sw->o_height = video->height;
+ sw->overlay_enabled = false;
+ sw->overlay = NULL;
+ sw->in_menu = false;
+
+ sw->vp.full_width = 1280;
+ sw->vp.full_height = 720;
+
+ // Sanity check
+ sw->vp.width = MIN(sw->vp.width, sw->vp.full_width);
+ sw->vp.height = MIN(sw->vp.height, sw->vp.full_height);
+
+ sw->vsync = video->vsync;
+ sw->rgb32 = video->rgb32;
+ sw->keep_aspect = true;
+ sw->should_resize = true;
+ sw->o_size = true;
+ sw->is_threaded = video->is_threaded;
+ sw->smooth = video->smooth;
+ sw->menu_texture.enable = false;
+
+ // Autoselect driver
+ if (input && input_data)
+ {
+ settings_t *settings = config_get_ptr();
+ switchinput = input_switch.init(settings->arrays.input_joypad_driver);
+ *input = switchinput ? &input_switch : NULL;
+ *input_data = switchinput;
+ }
+
+ font_driver_init_osd(sw, false,
+ video->is_threaded,
+ FONT_DRIVER_RENDER_SWITCH);
+
+ clear_screen(sw);
+
+ return sw;
+}
+
+static void switch_update_viewport(switch_video_t *sw,
+ video_frame_info_t *video_info)
+{
+ settings_t *settings = config_get_ptr();
+ int x = 0;
+ int y = 0;
+ float desired_aspect = 0.0f;
+ float width = sw->vp.full_width;
+ float height = sw->vp.full_height;
+
+ if (sw->o_size)
+ {
+ width = sw->o_width;
+ height = sw->o_height;
+ sw->vp.x = (int)(((float)sw->vp.full_width - width)) / 2;
+ sw->vp.y = (int)(((float)sw->vp.full_height - height)) / 2;
+
+ sw->vp.width = width;
+ sw->vp.height = height;
+
+ return;
+ }
+
+ desired_aspect = video_driver_get_aspect_ratio();
+
+ /* We crash if >1.0f */
+ printf("[Video] Aspect: %f\n", desired_aspect);
+ /*if (desired_aspect > 1.8f)
+ desired_aspect = 1.7778f;
+
+ if (desired_aspect < 1.2f && desired_aspect != 0.0f)
+ desired_aspect = 1.0f;*/
+
+ if (settings->bools.video_scale_integer)
+ {
+ video_viewport_get_scaled_integer(&sw->vp, sw->vp.full_width, sw->vp.full_height, desired_aspect, sw->keep_aspect);
+ }
+ else if (sw->keep_aspect)
+ {
+#if defined(HAVE_MENU)
+ if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
+ {
+ sw->vp.x = sw->vp.y = 0;
+ sw->vp.width = width;
+ sw->vp.height = height;
+ }
+ else
+#endif
+ {
+ float delta;
+ float device_aspect = ((float)sw->vp.full_width) / sw->vp.full_height;
+
+ if (fabsf(device_aspect - desired_aspect) < 0.0001f)
+ {
+ /*
+ * If the aspect ratios of screen and desired aspect
+ * ratio are sufficiently equal (floating point stuff),
+ * assume they are actually equal.
+ */
+ }
+ else if (device_aspect > desired_aspect)
+ {
+ delta = (desired_aspect / device_aspect - 1.0f) / 2.0f + 0.5f;
+ x = (int)roundf(width * (0.5f - delta));
+ width = (unsigned)roundf(2.0f * width * delta);
+ }
+ else
+ {
+ delta = (device_aspect / desired_aspect - 1.0f) / 2.0f + 0.5f;
+ y = (int)roundf(height * (0.5f - delta));
+ height = (unsigned)roundf(2.0f * height * delta);
+ }
+ }
+
+ sw->vp.x = x;
+ sw->vp.y = y;
+
+ sw->vp.width = width;
+ sw->vp.height = height;
+ }
+ else
+ {
+ sw->vp.x = sw->vp.y = 0;
+ sw->vp.width = width;
+ sw->vp.height = height;
+ }
+}
+
+static void switch_set_aspect_ratio(void *data, unsigned aspect_ratio_idx)
+{
+ switch_video_t *sw = (switch_video_t *)data;
+
+ if (!sw)
+ return;
+
+ sw->keep_aspect = true;
+ sw->o_size = false;
+
+ settings_t *settings = config_get_ptr();
+
+ switch (aspect_ratio_idx)
+ {
+ case ASPECT_RATIO_SQUARE:
+ video_driver_set_viewport_square_pixel();
+ break;
+
+ case ASPECT_RATIO_CORE:
+ video_driver_set_viewport_core();
+ sw->o_size = true;
+ sw->keep_aspect = false;
+ break;
+
+ case ASPECT_RATIO_CONFIG:
+ video_driver_set_viewport_config();
+ break;
+
+ case ASPECT_RATIO_CUSTOM:
+ if (settings->bools.video_scale_integer)
+ {
+ video_driver_set_viewport_core();
+ sw->o_size = true;
+ sw->keep_aspect = false;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ video_driver_set_aspect_ratio_value(aspectratio_lut[aspect_ratio_idx].value);
+
+ sw->should_resize = true;
+}
+
+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;
+ uint32_t *out_buffer = NULL;
+ bool ffwd_mode = video_info->input_driver_nonblock_state;
+
+ if (!frame)
+ return true;
+
+ if (ffwd_mode && !sw->is_threaded)
+ {
+ // render every 4th frame when in ffwd mode and not threaded
+ if ((frame_count % 4) != 0)
+ return true;
+ }
+
+ if (sw->should_resize || width != sw->last_width || height != sw->last_height)
+ {
+ printf("[Video] Requesting new size: width %i height %i\n", width, height);
+ printf("[Video] fw: %i fh: %i w: %i h: %i x: %i y: %i\n", sw->vp.full_width, sw->vp.full_height, sw->vp.width, sw->vp.height, sw->vp.x, sw->vp.y);
+ switch_update_viewport(sw, video_info);
+ printf("[Video] fw: %i fh: %i w: %i h: %i x: %i y: %i\n", sw->vp.full_width, sw->vp.full_height, sw->vp.width, sw->vp.height, sw->vp.x, sw->vp.y);
+
+ // Sanity check
+ sw->vp.width = MIN(sw->vp.width, sw->vp.full_width);
+ sw->vp.height = MIN(sw->vp.height, sw->vp.full_height);
+
+ scaler_ctx_gen_reset(&sw->scaler);
+
+ sw->scaler.in_width = width;
+ sw->scaler.in_height = height;
+ sw->scaler.in_stride = pitch;
+ sw->scaler.in_fmt = sw->rgb32 ? SCALER_FMT_ARGB8888 : SCALER_FMT_RGB565;
+
+ if (!sw->smooth)
+ {
+ sw->scaler.out_width = sw->vp.width;
+ sw->scaler.out_height = sw->vp.height;
+ sw->scaler.out_stride = sw->vp.full_width * sizeof(uint32_t);
+ }
+ else
+ {
+ sw->scaler.out_width = width;
+ sw->scaler.out_height = height;
+ sw->scaler.out_stride = width * sizeof(uint32_t);
+
+ float screen_ratio = (float)sw->vp.full_width / sw->vp.full_height;
+ float tgt_ratio = (float)sw->vp.width / sw->vp.height;
+
+ sw->hw_scale.width = ceil(screen_ratio / tgt_ratio * sw->scaler.out_width);
+ sw->hw_scale.height = sw->scaler.out_height;
+ sw->hw_scale.x_offset = ceil((sw->hw_scale.width - sw->scaler.out_width) / 2.0);
+ if (!video_info->menu_is_alive)
+ {
+ clear_screen(sw);
+ gfxConfigureResolution(sw->hw_scale.width, sw->hw_scale.height);
+ }
+ }
+ sw->scaler.out_fmt = SCALER_FMT_ABGR8888;
+
+ sw->scaler.scaler_type = SCALER_TYPE_POINT;
+
+ if (!scaler_ctx_gen_filter(&sw->scaler))
+ {
+ printf("failed to generate scaler for main image\n");
+ return false;
+ }
+
+ sw->last_width = width;
+ sw->last_height = height;
+
+ sw->should_resize = false;
+ }
+
+ out_buffer = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
+
+ if (sw->in_menu && !video_info->menu_is_alive && sw->smooth)
+ {
+ memset(out_buffer, 0, sw->vp.full_width * sw->vp.full_height * 4);
+ gfxConfigureResolution(sw->hw_scale.width, sw->hw_scale.height);
+ }
+ sw->in_menu = video_info->menu_is_alive;
+
+ if (sw->menu_texture.enable)
+ {
+ menu_driver_frame(video_info);
+
+ if (sw->menu_texture.pixels)
+ {
+#ifdef HAVE_NXRGUI
+ gfx_slow_swizzling_blit(out_buffer, nx_backgroundImage, sw->vp.full_width, sw->vp.full_height, 0, 0, false);
+#else
+ memset(out_buffer, 0, gfxGetFramebufferSize());
+#endif
+ scaler_ctx_scale(&sw->menu_texture.scaler, sw->tmp_image + ((sw->vp.full_height - sw->menu_texture.tgth) / 2) * sw->vp.full_width + ((sw->vp.full_width - sw->menu_texture.tgtw) / 2), sw->menu_texture.pixels);
+ gfx_slow_swizzling_blit(out_buffer, sw->tmp_image, sw->vp.full_width, sw->vp.full_height, 0, 0, true);
+ }
+ }
+ else if (sw->smooth) // bilinear
+ {
+ struct scaler_ctx *ctx = &sw->scaler;
+ scaler_ctx_scale_direct(ctx, sw->image, frame);
+ int w = sw->scaler.out_width;
+ int h = sw->scaler.out_height;
+ for (int y = 0; y < h; y++)
+ for (int x = 0; x < w; x++)
+ out_buffer[gfxGetFramebufferDisplayOffset(x + sw->hw_scale.x_offset, y)] = sw->image[y * w + x];
+ }
+ else
+ {
+ struct scaler_ctx *ctx = &sw->scaler;
+ scaler_ctx_scale(ctx, sw->image + (sw->vp.y * sw->vp.full_width) + sw->vp.x, frame);
+ gfx_slow_swizzling_blit(out_buffer, sw->image, sw->vp.full_width, sw->vp.full_height, 0, 0, false);
+#ifdef HAVE_NXRGUI
+ if (tmp_overlay)
+ {
+ gfx_slow_swizzling_blit(out_buffer, tmp_overlay, sw->vp.full_width, sw->vp.full_height, 0, 0, true);
+ }
+#endif
+ }
+
+ if (video_info->statistics_show && !sw->smooth)
+ {
+ struct font_params *osd_params = (struct font_params *)&video_info->osd_stat_params;
+
+ if (osd_params)
+ font_driver_render_msg(video_info, NULL, video_info->stat_text,
+ (const struct font_params *)&video_info->osd_stat_params);
+ }
+
+ if (msg)
+ font_driver_render_msg(video_info, NULL, msg, NULL);
+
+ gfxFlushBuffers();
+ gfxSwapBuffers();
+ if (sw->vsync || video_info->menu_is_alive)
+ gfxWaitForVsync();
+
+ 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;
+ if (sw->menu_texture.pixels)
+ free(sw->menu_texture.pixels);
+
+ free(sw);
+}
+
+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;
+ if (!sw)
+ return;
+ 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_set_texture_frame(
+ void *data, const void *frame, bool rgb32,
+ unsigned width, unsigned height, float alpha)
+{
+ switch_video_t *sw = data;
+ size_t sz = width * height * (rgb32 ? 4 : 2);
+
+ if (!sw->menu_texture.pixels ||
+ sw->menu_texture.width != width ||
+ sw->menu_texture.height != height)
+ {
+ if (sw->menu_texture.pixels)
+ realloc(sw->menu_texture.pixels, sz);
+ else
+ sw->menu_texture.pixels = malloc(sz);
+
+ if (!sw->menu_texture.pixels)
+ {
+ printf("failed to allocate buffer for menu texture\n");
+ return;
+ }
+
+ int xsf = 1280 / width;
+ int ysf = 720 / height;
+ int sf = xsf;
+
+ if (ysf < sf)
+ sf = ysf;
+
+ sw->menu_texture.width = width;
+ sw->menu_texture.height = height;
+ sw->menu_texture.tgtw = width * sf;
+ sw->menu_texture.tgth = height * sf;
+
+ struct scaler_ctx *sctx = &sw->menu_texture.scaler;
+ scaler_ctx_gen_reset(sctx);
+
+ sctx->in_width = width;
+ sctx->in_height = height;
+ sctx->in_stride = width * (rgb32 ? 4 : 2);
+ sctx->in_fmt = rgb32 ? SCALER_FMT_ARGB8888 : SCALER_FMT_RGB565;
+ sctx->out_width = sw->menu_texture.tgtw;
+ sctx->out_height = sw->menu_texture.tgth;
+ sctx->out_stride = 1280 * 4;
+ sctx->out_fmt = SCALER_FMT_ABGR8888;
+
+ sctx->scaler_type = SCALER_TYPE_POINT;
+
+ if (!scaler_ctx_gen_filter(sctx))
+ {
+ printf("failed to generate scaler for menu texture\n");
+ return;
+ }
+ }
+
+ memcpy(sw->menu_texture.pixels, frame, sz);
+}
+
+static void switch_apply_state_changes(void *data)
+{
+ (void)data;
+}
+
+static void switch_set_texture_enable(void *data, bool enable, bool full_screen)
+{
+ switch_video_t *sw = data;
+
+ if (!sw->menu_texture.enable && enable)
+ gfxConfigureResolution(sw->vp.full_width, sw->vp.full_height);
+ else if (!enable && sw->menu_texture.enable && sw->smooth)
+ {
+ clear_screen(sw);
+ gfxConfigureResolution(sw->hw_scale.width, sw->hw_scale.height);
+ }
+
+ sw->menu_texture.enable = enable;
+ sw->menu_texture.fullscreen = full_screen;
+}
+
+static void switch_set_osd_msg(void *data,
+ video_frame_info_t *video_info,
+ const char *msg,
+ const void *params, void *font)
+{
+ switch_video_t *sw = (switch_video_t *)data;
+
+ if (sw)
+ font_driver_render_msg(video_info, font, msg, params);
+}
+
+#ifdef HAVE_OVERLAY
+static void switch_overlay_enable(void *data, bool state)
+{
+ printf("[Video] Enabled Overlay\n");
+
+ switch_video_t *swa = (switch_video_t *)data;
+
+ if (!swa)
+ return;
+
+ swa->overlay_enabled = state;
+}
+
+static bool switch_overlay_load(void *data,
+ const void *image_data, unsigned num_images)
+{
+ switch_video_t *swa = (switch_video_t *)data;
+
+ struct texture_image *images = (struct texture_image *)image_data;
+
+ if (!swa)
+ return false;
+
+ swa->overlay = images;
+ swa->overlay_enabled = true;
+
+ return true;
+}
+
+static void switch_overlay_tex_geom(void *data,
+ unsigned idx, float x, float y, float w, float h)
+{
+ switch_video_t *swa = (switch_video_t *)data;
+
+ if (!swa)
+ return;
+}
+
+static void switch_overlay_vertex_geom(void *data,
+ unsigned idx, float x, float y, float w, float h)
+{
+ switch_video_t *swa = (switch_video_t *)data;
+
+ if (!swa)
+ return;
+}
+
+static void switch_overlay_full_screen(void *data, bool enable)
+{
+ (void)data;
+ (void)enable;
+}
+
+static void switch_overlay_set_alpha(void *data, unsigned idx, float mod)
+{
+ (void)data;
+ (void)idx;
+ (void)mod;
+}
+
+static const video_overlay_interface_t switch_overlay = {
+ switch_overlay_enable,
+ switch_overlay_load,
+ switch_overlay_tex_geom,
+ switch_overlay_vertex_geom,
+ switch_overlay_full_screen,
+ switch_overlay_set_alpha,
+};
+
+void switch_overlay_interface(void *data, const video_overlay_interface_t **iface)
+{
+ switch_video_t *swa = (switch_video_t *)data;
+ if (!swa)
+ return;
+ *iface = &switch_overlay;
+}
+
+#endif
+
+static const video_poke_interface_t switch_poke_interface = {
+ NULL, /* get_flags */
+ NULL, /* set_coords */
+ NULL, /* set_mvp */
+ NULL, /* load_texture */
+ NULL, /* unload_texture */
+ NULL, /* set_video_mode */
+ NULL, /* 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 */
+ switch_set_aspect_ratio, /* set_aspect_ratio */
+ switch_apply_state_changes, /* apply_state_changes */
+ switch_set_texture_frame,
+ switch_set_texture_enable,
+ switch_set_osd_msg,
+ NULL, /* show_mouse */
+ NULL, /* grab_mouse_toggle */
+ NULL, /* get_current_shader */
+ NULL, /* get_current_software_framebuffer */
+ NULL, /* get_hw_render_interface */
+};
+
+static void switch_get_poke_interface(void *data,
+ const video_poke_interface_t **iface)
+{
+ (void)data;
+ *iface = &switch_poke_interface;
+}
+
+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
+ switch_overlay_interface, /* switch_overlay_interface */
+#endif
+ switch_get_poke_interface,
+};
+
+/* vim: set ts=6 sw=6 sts=6: */
diff --git a/libretro-common/rthreads/switch_pthread.h b/libretro-common/rthreads/switch_pthread.h
index 5d51194666..7dc32adfca 100644
--- a/libretro-common/rthreads/switch_pthread.h
+++ b/libretro-common/rthreads/switch_pthread.h
@@ -1,207 +1,207 @@
-/* Copyright (C) 2018 - M4xw , RetroArch Team
- *
- * ---------------------------------------------------------------------------------------
- * The following license statement only applies to this file (switch_pthread.h).
- * ---------------------------------------------------------------------------------------
- *
- * Permission is hereby granted, free of charge,
- * to any person obtaining a copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _SWITCH_PTHREAD_WRAP_
-#define _SWITCH_PTHREAD_WRAP_
-
-#include
-#include
-#include
-#include
-
-#include "../include/retro_inline.h"
-#include "../../verbosity.h"
-
-#define THREADVARS_MAGIC 0x21545624 // !TV$
-
-// This structure is exactly 0x20 bytes, if more is needed modify getThreadVars() below
-typedef struct
-{
- // Magic value used to check if the struct is initialized
- u32 magic;
-
- // Thread handle, for mutexes
- Handle handle;
-
- // Pointer to the current thread (if exists)
- Thread *thread_ptr;
-
- // Pointer to this thread's newlib state
- struct _reent *reent;
-
- // Pointer to this thread's thread-local segment
- void *tls_tp; // !! Offset needs to be TLS+0x1F8 for __aarch64_read_tp !!
-} ThreadVars;
-
-static INLINE ThreadVars *getThreadVars(void)
-{
- return (ThreadVars *)((u8 *)armGetTls() + 0x1E0);
-}
-
-#define STACKSIZE (8 * 1024)
-
-/* libnx threads return void but pthreads return void pointer */
-
-static uint32_t threadCounter = 1;
-
-int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
-{
- u32 prio = 0;
- Thread new_switch_thread;
-
- svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
-
- // Launch threads on Core 1
- int rc = threadCreate(&new_switch_thread, (void (*)(void *))start_routine, arg, STACKSIZE, prio - 1, 1);
-
- if (R_FAILED(rc))
- {
- return EAGAIN;
- }
-
- printf("[Threading]: Starting Thread(#%i)\n", threadCounter);
- if (R_FAILED(threadStart(&new_switch_thread)))
- {
- threadClose(&new_switch_thread);
- return -1;
- }
-
- *thread = new_switch_thread;
-
- return 0;
-}
-
-void pthread_exit(void *retval)
-{
- (void)retval;
- printf("[Threading]: Exiting Thread\n");
- svcExitThread();
-}
-
-static INLINE Thread threadGetCurrent(void)
-{
- ThreadVars *tv = getThreadVars();
- return *tv->thread_ptr;
-}
-
-static INLINE pthread_t pthread_self(void)
-{
- return threadGetCurrent();
-}
-
-static INLINE int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
-{
- mutexInit(mutex);
-
- return 0;
-}
-
-INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
-{
- // Nothing
- *mutex = 0;
-
- return 0;
-}
-
-static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
-{
- mutexLock(mutex);
- return 0;
-}
-
-static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
-{
- mutexUnlock(mutex);
-
- return 0;
-}
-
-INLINE int pthread_detach(pthread_t thread)
-{
- (void)thread;
- // Nothing for now
- return 0;
-}
-
-static INLINE int pthread_join(pthread_t thread, void **retval)
-{
- printf("[Threading]: Waiting for Thread Exit\n");
- threadWaitForExit(&thread);
- threadClose(&thread);
-
- return 0;
-}
-
-static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
-{
- return mutexTryLock(mutex) ? 0 : 1;
-}
-
-static INLINE int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
-{
- condvarWait(cond, mutex);
-
- return 0;
-}
-
-static INLINE int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
-{
- condvarWaitTimeout(cond, mutex, abstime->tv_nsec);
-
- return 0;
-}
-
-static INLINE int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
-{
- condvarInit(cond);
-
- return 0;
-}
-
-static INLINE int pthread_cond_signal(pthread_cond_t *cond)
-{
- condvarWakeOne(cond);
- return 0;
-}
-
-static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
-{
- condvarWakeAll(cond);
- return 0;
-}
-
-INLINE int pthread_cond_destroy(pthread_cond_t *cond)
-{
- // Nothing
- return 0;
-}
-
-INLINE int pthread_equal(pthread_t t1, pthread_t t2)
-{
- if (t1.handle == t2.handle)
- return 1;
-
- return 0;
-}
-
-#endif
+/* Copyright (C) 2018 - M4xw , RetroArch Team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (switch_pthread.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _SWITCH_PTHREAD_WRAP_
+#define _SWITCH_PTHREAD_WRAP_
+
+#include
+#include
+#include
+#include
+
+#include "../include/retro_inline.h"
+#include "../../verbosity.h"
+
+#define THREADVARS_MAGIC 0x21545624 // !TV$
+
+// This structure is exactly 0x20 bytes, if more is needed modify getThreadVars() below
+typedef struct
+{
+ // Magic value used to check if the struct is initialized
+ u32 magic;
+
+ // Thread handle, for mutexes
+ Handle handle;
+
+ // Pointer to the current thread (if exists)
+ Thread *thread_ptr;
+
+ // Pointer to this thread's newlib state
+ struct _reent *reent;
+
+ // Pointer to this thread's thread-local segment
+ void *tls_tp; // !! Offset needs to be TLS+0x1F8 for __aarch64_read_tp !!
+} ThreadVars;
+
+static INLINE ThreadVars *getThreadVars(void)
+{
+ return (ThreadVars *)((u8 *)armGetTls() + 0x1E0);
+}
+
+#define STACKSIZE (8 * 1024)
+
+/* libnx threads return void but pthreads return void pointer */
+
+static uint32_t threadCounter = 1;
+
+int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
+{
+ u32 prio = 0;
+ Thread new_switch_thread;
+
+ svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
+
+ // Launch threads on Core 1
+ int rc = threadCreate(&new_switch_thread, (void (*)(void *))start_routine, arg, STACKSIZE, prio - 1, 1);
+
+ if (R_FAILED(rc))
+ {
+ return EAGAIN;
+ }
+
+ printf("[Threading]: Starting Thread(#%i)\n", threadCounter);
+ if (R_FAILED(threadStart(&new_switch_thread)))
+ {
+ threadClose(&new_switch_thread);
+ return -1;
+ }
+
+ *thread = new_switch_thread;
+
+ return 0;
+}
+
+void pthread_exit(void *retval)
+{
+ (void)retval;
+ printf("[Threading]: Exiting Thread\n");
+ svcExitThread();
+}
+
+static INLINE Thread threadGetCurrent(void)
+{
+ ThreadVars *tv = getThreadVars();
+ return *tv->thread_ptr;
+}
+
+static INLINE pthread_t pthread_self(void)
+{
+ return threadGetCurrent();
+}
+
+static INLINE int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
+{
+ mutexInit(mutex);
+
+ return 0;
+}
+
+INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+ // Nothing
+ *mutex = 0;
+
+ return 0;
+}
+
+static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ mutexLock(mutex);
+ return 0;
+}
+
+static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+ mutexUnlock(mutex);
+
+ return 0;
+}
+
+INLINE int pthread_detach(pthread_t thread)
+{
+ (void)thread;
+ // Nothing for now
+ return 0;
+}
+
+static INLINE int pthread_join(pthread_t thread, void **retval)
+{
+ printf("[Threading]: Waiting for Thread Exit\n");
+ threadWaitForExit(&thread);
+ threadClose(&thread);
+
+ return 0;
+}
+
+static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ return mutexTryLock(mutex) ? 0 : 1;
+}
+
+static INLINE int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ condvarWait(cond, mutex);
+
+ return 0;
+}
+
+static INLINE int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
+{
+ condvarWaitTimeout(cond, mutex, abstime->tv_nsec);
+
+ return 0;
+}
+
+static INLINE int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
+{
+ condvarInit(cond);
+
+ return 0;
+}
+
+static INLINE int pthread_cond_signal(pthread_cond_t *cond)
+{
+ condvarWakeOne(cond);
+ return 0;
+}
+
+static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+ condvarWakeAll(cond);
+ return 0;
+}
+
+INLINE int pthread_cond_destroy(pthread_cond_t *cond)
+{
+ // Nothing
+ return 0;
+}
+
+INLINE int pthread_equal(pthread_t t1, pthread_t t2)
+{
+ if (t1.handle == t2.handle)
+ return 1;
+
+ return 0;
+}
+
+#endif