Merge pull request #7220 from reswitched/master

[NSW] SDK Compat Fixups
This commit is contained in:
Twinaphex 2018-09-15 16:33:52 +02:00 committed by GitHub
commit 13c22c47b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 2390 additions and 2172 deletions

View File

@ -836,7 +836,9 @@ ifeq ($(TARGET), retroarch_switch)
OBJ += gfx/drivers/switch_gfx.o \ OBJ += gfx/drivers/switch_gfx.o \
input/drivers/switch_input.o \ input/drivers/switch_input.o \
input/drivers_joypad/switch_joypad.o \ input/drivers_joypad/switch_joypad.o \
audio/drivers/switch_audio.o audio/drivers/switch_audio.o \
audio/drivers/switch_nx_thread_audio.o \
frontend/drivers/platform_switch.o
endif endif
endif endif

View File

@ -42,7 +42,7 @@ endif
ifeq ($(strip $(LIBTRANSISTOR_HOME)),) ifeq ($(strip $(LIBTRANSISTOR_HOME)),)
$(error "Please set LIBTRANSISTOR_HOME in your environment. export LIBTRANSISTOR_HOME=<path t>o libtransistor") $(error "Please set LIBTRANSISTOR_HOME in your environment. export LIBTRANSISTOR_HOME=<path/to/libtransistor/dist/>")
endif endif
include $(LIBTRANSISTOR_HOME)/libtransistor.mk include $(LIBTRANSISTOR_HOME)/libtransistor.mk
@ -52,7 +52,7 @@ LIBDIRS := -L.
TARGETS := $(TARGET).nro TARGETS := $(TARGET).nro
CFLAGS += $(INCDIRS) $(DEFINES) -Wunused-command-line-argument CFLAGS += $(INCDIRS) $(DEFINES) -Wno-unused-command-line-argument -Werror-implicit-function-declaration
all: $(TARGETS) all: $(TARGETS)

View File

@ -125,9 +125,7 @@ static const audio_driver_t *audio_drivers[] = {
#endif #endif
#ifdef SWITCH #ifdef SWITCH
&audio_switch, &audio_switch,
#ifdef HAVE_LIBNX
&audio_switch_thread, &audio_switch_thread,
#endif
#endif #endif
&audio_null, &audio_null,
NULL, NULL,

View File

@ -1,5 +1,5 @@
/* RetroArch - A frontend for libretro. /* RetroArch - A frontend for libretro.
* Copyright (C) 2018 - misson2000 * Copyright (C) 2018 - misson20000
* Copyright (C) 2018 - m4xw * Copyright (C) 2018 - m4xw
* *
* RetroArch is free software: you can redistribute it and/or modify it under the terms * RetroArch is free software: you can redistribute it and/or modify it under the terms
@ -19,13 +19,7 @@
#include <malloc.h> #include <malloc.h>
#include <stdint.h> #include <stdint.h>
#ifdef HAVE_LIBNX #include "switch_audio_compat.h"
#include <switch.h>
#else
#include <libtransistor/nx.h>
#include <libtransistor/alloc_pages.h>
#endif
#include "../audio_driver.h" #include "../audio_driver.h"
#include "../../verbosity.h" #include "../../verbosity.h"
@ -35,22 +29,6 @@
#define BUFFER_COUNT 3 #define BUFFER_COUNT 3
#endif #endif
#ifdef HAVE_LIBNX
#define switch_audio_ipc_init audoutInitialize
#define switch_audio_ipc_output_get_released_buffer(a, b) audoutGetReleasedAudioOutBuffer(&a->current_buffer, &b)
#define switch_audio_ipc_output_append_buffer(a, b) audoutAppendAudioOutBuffer(&b)
#define switch_audio_ipc_output_stop(a) audoutStopAudioOut()
#define switch_audio_ipc_output_start(a) audoutStartAudioOut()
#define audio_output_buffer_t AudioOutBuffer
#else
#define switch_audio_ipc_init audio_ipc_init
#define switch_audio_ipc_output_get_released_buffer(a, b) audio_ipc_output_get_released_buffer(&a->output, &b, &a->current_buffer)
#define switch_audio_ipc_output_append_buffer(a, b) audio_ipc_output_append_buffer(&a->output, &b)
#define switch_audio_ipc_output_stop(a) audio_ipc_output_stop(&a->output)
#define switch_audio_ipc_output_start(a) audio_ipc_output_start(&a->output)
#define audio_output_buffer_t audio_output_buffer_t
#endif
static const int sample_rate = 48000; static const int sample_rate = 48000;
static const int max_num_samples = sample_rate; static const int max_num_samples = sample_rate;
static const int num_channels = 2; static const int num_channels = 2;
@ -62,8 +40,8 @@ typedef struct
bool is_paused; bool is_paused;
uint64_t last_append; uint64_t last_append;
unsigned latency; unsigned latency;
audio_output_buffer_t buffers[BUFFER_COUNT]; compat_audio_out_buffer buffers[BUFFER_COUNT];
audio_output_buffer_t *current_buffer; compat_audio_out_buffer *current_buffer;
#ifndef HAVE_LIBNX #ifndef HAVE_LIBNX
audio_output_t output; audio_output_t output;
@ -155,13 +133,8 @@ static ssize_t switch_audio_write(void *data, const void *buf, size_t size)
if (swa->current_buffer->data_size > (48000 * swa->latency) / 1000) if (swa->current_buffer->data_size > (48000 * swa->latency) / 1000)
{ {
#ifdef HAVE_LIBNX
if (switch_audio_ipc_output_append_buffer(swa, *swa->current_buffer) != 0)
return -1;
#else
if (switch_audio_ipc_output_append_buffer(swa, swa->current_buffer) != 0) if (switch_audio_ipc_output_append_buffer(swa, swa->current_buffer) != 0)
return -1; return -1;
#endif
swa->current_buffer = NULL; swa->current_buffer = NULL;
} }
@ -339,7 +312,7 @@ static void *switch_audio_init(const char *device,
goto fail_audio_output; goto fail_audio_output;
#endif #endif
if (switch_audio_ipc_output_append_buffer(swa, swa->buffers[i]) != 0) if (switch_audio_ipc_output_append_buffer(swa, &swa->buffers[i]) != 0)
goto fail_audio_output; goto fail_audio_output;
} }

View File

@ -0,0 +1,90 @@
#pragma once
#ifdef HAVE_LIBNX
#include <switch.h>
#else
#include <libtransistor/nx.h>
#endif
#ifdef HAVE_LIBNX
// libnx definitions
// threading
typedef Mutex compat_mutex;
typedef Thread compat_thread;
typedef CondVar compat_condvar;
#define compat_thread_create(thread, func, data, stack_size, prio, cpu) \
threadCreate(thread, func, data, stack_size, prio, cpu)
#define compat_thread_start(thread) \
threadStart(thread)
#define compat_thread_join(thread) \
threadWaitForExit(thread)
#define compat_thread_close(thread) \
threadClose(thread)
#define compat_mutex_create(mutex) \
mutexInit(mutex)
#define compat_mutex_lock(mutex) \
mutexLock(mutex)
#define compat_mutex_unlock(mutex) \
mutexUnlock(mutex)
#define compat_condvar_create(condvar) \
condvarInit(condvar)
#define compat_condvar_wait(condvar, mutex) \
condvarWait(condvar, mutex)
#define compat_condvar_wake_all(condvar) \
condvarWakeAll(condvar)
// audio
typedef AudioOutBuffer compat_audio_out_buffer;
#define switch_audio_ipc_init audoutInitialize
#define switch_audio_ipc_finalize audoutExit
#define switch_audio_ipc_output_get_released_buffer(a, b) audoutGetReleasedAudioOutBuffer(&a->current_buffer, &b)
#define switch_audio_ipc_output_append_buffer(a, b) audoutAppendAudioOutBuffer(b)
#define switch_audio_ipc_output_stop(a) audoutStopAudioOut()
#define switch_audio_ipc_output_start(a) audoutStartAudioOut()
#else
// libtransistor definitions
typedef result_t Result;
#define R_FAILED(r) ((r) != RESULT_OK)
// threading
typedef trn_mutex_t compat_mutex;
typedef trn_thread_t compat_thread;
typedef trn_condvar_t compat_condvar;
#define compat_thread_create(thread, func, data, stack_size, prio, cpu) \
trn_thread_create(thread, func, data, prio, cpu, stack_size, NULL)
#define compat_thread_start(thread) \
trn_thread_start(thread)
#define compat_thread_join(thread) \
trn_thread_join(thread, -1)
#define compat_thread_close(thread) \
trn_thread_destroy(thread)
#define compat_mutex_create(mutex) \
trn_mutex_create(mutex)
#define compat_mutex_lock(mutex) \
trn_mutex_lock(mutex)
#define compat_mutex_unlock(mutex) \
trn_mutex_unlock(mutex)
#define compat_condvar_create(condvar) \
trn_condvar_create(condvar)
#define compat_condvar_wait(condvar, mutex) \
trn_condvar_wait(condvar, mutex, -1)
#define compat_condvar_wake_all(condvar) \
trn_condvar_signal(condvar, -1)
// audio
typedef audio_output_buffer_t compat_audio_out_buffer;
#define switch_audio_ipc_init audio_ipc_init
#define switch_audio_ipc_finalize audio_ipc_finalize
#define switch_audio_ipc_output_get_released_buffer(a, b) audio_ipc_output_get_released_buffer(&a->output, &b, &a->current_buffer)
#define switch_audio_ipc_output_append_buffer(a, b) audio_ipc_output_append_buffer(&a->output, b)
#define switch_audio_ipc_output_stop(a) audio_ipc_output_stop(&a->output)
#define switch_audio_ipc_output_start(a) audio_ipc_output_start(&a->output)
#endif

View File

@ -1,5 +1,5 @@
/* RetroArch - A frontend for libretro. /* RetroArch - A frontend for libretro.
* Copyright (C) 2018 - misson2000 * Copyright (C) 2018 - misson20000
* Copyright (C) 2018 - m4xw * Copyright (C) 2018 - m4xw
* Copyright (C) 2018 - lifajucejo * Copyright (C) 2018 - lifajucejo
* *
@ -21,7 +21,11 @@
#include <stdint.h> #include <stdint.h>
#include <sys/unistd.h> #include <sys/unistd.h>
#ifdef HAVE_LIBNX
#include <switch.h> #include <switch.h>
#else
#include <libtransistor/nx.h>
#endif
#include <queues/fifo_queue.h> #include <queues/fifo_queue.h>
#include "../audio_driver.h" #include "../audio_driver.h"
@ -29,27 +33,22 @@
#include "../../tasks/tasks_internal.h" #include "../../tasks/tasks_internal.h"
#define THREAD_STACK_SIZE (1024 * 8) #include "switch_audio_compat.h"
#define AUDIO_THREAD_CPU 2 static const size_t thread_stack_size = 1024 * 8;
static const int thread_preferred_cpu = 2;
#define CHANNELCOUNT 2 static const int channel_count = 2;
#define BYTESPERSAMPLE sizeof(uint16_t) static const size_t sample_size = sizeof(uint16_t);
#define SAMPLE_SIZE (CHANNELCOUNT * BYTESPERSAMPLE) static const size_t frame_size = channel_count * sample_size;
#define AUDIO_BUFFER_COUNT 2 #define AUDIO_BUFFER_COUNT 2
static inline void lockMutex(Mutex* mtx)
{
mutexLock(mtx);
}
typedef struct typedef struct
{ {
fifo_buffer_t* fifo; fifo_buffer_t* fifo;
Mutex fifoLock; compat_mutex fifoLock;
CondVar cond; compat_condvar cond;
Mutex condLock; compat_mutex condLock;
size_t fifoSize; size_t fifoSize;
@ -57,11 +56,16 @@ typedef struct
bool nonblocking; bool nonblocking;
bool is_paused; bool is_paused;
AudioOutBuffer buffer[AUDIO_BUFFER_COUNT]; compat_audio_out_buffer buffers[AUDIO_BUFFER_COUNT];
Thread thread; compat_thread thread;
unsigned latency; unsigned latency;
uint32_t sampleRate; uint32_t sampleRate;
#ifndef HAVE_LIBNX
audio_output_t output;
handle_t event;
#endif
} switch_thread_audio_t; } switch_thread_audio_t;
static void mainLoop(void* data) static void mainLoop(void* data)
@ -73,27 +77,23 @@ static void mainLoop(void* data)
RARCH_LOG("[Audio]: start mainLoop cpu %u tid %u\n", svcGetCurrentProcessorNumber(), swa->thread.handle); RARCH_LOG("[Audio]: start mainLoop cpu %u tid %u\n", svcGetCurrentProcessorNumber(), swa->thread.handle);
for (int i = 0; i < AUDIO_BUFFER_COUNT; i++) compat_audio_out_buffer* released_out_buffer = NULL;
{ uint32_t released_out_count;
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; Result rc;
while (swa->running) while (swa->running)
{ {
if (!released_out_buffer) if (!released_out_buffer)
{ {
#ifdef HAVE_LIBNX
rc = audoutWaitPlayFinish(&released_out_buffer, &released_out_count, U64_MAX); rc = audoutWaitPlayFinish(&released_out_buffer, &released_out_count, U64_MAX);
#else
uint32_t handle_idx = 0;
svcWaitSynchronization(&handle_idx, &swa->event, 1, 33333333);
svcResetSignal(swa->event);
rc = audio_ipc_output_get_released_buffer(&swa->output, &released_out_count, &released_out_buffer);
#endif
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
swa->running = false; swa->running = false;
@ -105,20 +105,27 @@ static void mainLoop(void* data)
size_t bufAvail = released_out_buffer->buffer_size - released_out_buffer->data_size; size_t bufAvail = released_out_buffer->buffer_size - released_out_buffer->data_size;
lockMutex(&swa->fifoLock); compat_mutex_lock(&swa->fifoLock);
size_t avail = fifo_read_avail(swa->fifo); size_t avail = fifo_read_avail(swa->fifo);
size_t to_write = MIN(avail, bufAvail); size_t to_write = MIN(avail, bufAvail);
if (to_write > 0) if (to_write > 0) {
fifo_read(swa->fifo, ((u8*)released_out_buffer->buffer) + released_out_buffer->data_size, to_write); uint8_t *base;
#ifdef HAVE_LIBNX
base = (uint8_t*) released_out_buffer->buffer;
#else
base = (uint8_t*) released_out_buffer->sample_data;
#endif
fifo_read(swa->fifo, base + released_out_buffer->data_size, to_write);
}
mutexUnlock(&swa->fifoLock); compat_mutex_unlock(&swa->fifoLock);
condvarWakeAll(&swa->cond); compat_condvar_wake_all(&swa->cond);
released_out_buffer->data_size += to_write; released_out_buffer->data_size += to_write;
if (released_out_buffer->data_size >= released_out_buffer->buffer_size / 2) if (released_out_buffer->data_size >= released_out_buffer->buffer_size / 2)
{ {
rc = audoutAppendAudioOutBuffer(released_out_buffer); rc = switch_audio_ipc_output_append_buffer(swa, released_out_buffer);
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
RARCH_LOG("[Audio]: audoutAppendAudioOutBuffer failed: %d\n", (int)rc); RARCH_LOG("[Audio]: audoutAppendAudioOutBuffer failed: %d\n", (int)rc);
@ -132,9 +139,11 @@ static void mainLoop(void* data)
static void *switch_thread_audio_init(const char *device, unsigned rate, unsigned latency, unsigned block_frames, unsigned *new_rate) static void *switch_thread_audio_init(const char *device, unsigned rate, unsigned latency, unsigned block_frames, unsigned *new_rate)
{ {
(void)device; (void)device;
switch_thread_audio_t *swa = (switch_thread_audio_t *)calloc(1, sizeof(switch_thread_audio_t)); char names[8][0x20];
uint32_t num_names = 0;
switch_thread_audio_t *swa = (switch_thread_audio_t *)calloc(1, sizeof(*swa));
if (!swa) if (!swa)
return NULL; return NULL;
@ -144,35 +153,101 @@ static void *switch_thread_audio_init(const char *device, unsigned rate, unsigne
swa->is_paused = true; swa->is_paused = true;
swa->latency = MAX(latency, 8); swa->latency = MAX(latency, 8);
Result rc = audoutInitialize(); Result rc = switch_audio_ipc_init();
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
RARCH_LOG("[Audio]: audio init failed %d\n", (int)rc); RARCH_LOG("[Audio]: audio init failed %d\n", (int)rc);
free(swa);
return NULL; return NULL;
} }
#ifdef HAVE_LIBNX
rc = audoutStartAudioOut(); rc = audoutStartAudioOut();
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
RARCH_LOG("[Audio]: audio start init failed: %d\n", (int)rc); RARCH_LOG("[Audio]: audio start init failed: %d\n", (int)rc);
return NULL; goto fail_audio_ipc;
} }
swa->sampleRate = audoutGetSampleRate(); swa->sampleRate = audoutGetSampleRate();
#else
if (audio_ipc_list_outputs(&names[0], 8, &num_names) != RESULT_OK) {
goto fail_audio_ipc;
}
if (num_names != 1) {
RARCH_ERR("[Audio]: got back more than one AudioOut\n");
goto fail_audio_ipc;
}
if (audio_ipc_open_output(names[0], &swa->output) != RESULT_OK) {
goto fail_audio_ipc;
}
swa->sampleRate = swa->output.sample_rate;
if (swa->output.num_channels != 2)
{
RARCH_ERR("expected %d channels, got %d\n", 2,
swa->output.num_channels);
goto fail_audio_output;
}
if (swa->output.sample_format != PCM_INT16)
{
RARCH_ERR("expected PCM_INT16, got %d\n", swa->output.sample_format);
goto fail_audio_output;
}
if (audio_ipc_output_register_buffer_event(&swa->output, &swa->event) != 0)
goto fail_audio_output;
#endif
*new_rate = swa->sampleRate; *new_rate = swa->sampleRate;
mutexInit(&swa->fifoLock);
swa->fifoSize = (swa->sampleRate * SAMPLE_SIZE * swa->latency) / 1000; for (int i = 0; i < AUDIO_BUFFER_COUNT; i++)
{
#ifdef HAVE_LIBNX
swa->buffers[i].next = NULL; /* Unused */
swa->buffers[i].data_offset = 0;
swa->buffers[i].buffer_size = swa->fifoSize;
swa->buffers[i].data_size = swa->buffers[i].buffer_size;
swa->buffers[i].buffer = memalign(0x1000, swa->buffers[i].buffer_size);
if (swa->buffers[i].buffer == NULL)
goto fail;
memset(swa->buffers[i].buffer, 0, swa->buffers[i].buffer_size);
#else
swa->buffers[i].ptr = &swa->buffers[i].sample_data;
swa->buffers[i].unknown = 0;
swa->buffers[i].buffer_size = swa->fifoSize;
swa->buffers[i].data_size = swa->buffers[i].buffer_size;
swa->buffers[i].sample_data = alloc_pages(swa->buffers[i].buffer_size, swa->buffers[i].buffer_size, NULL);
if (swa->buffers[i].sample_data == NULL)
goto fail_audio_output;
memset(swa->buffers[i].sample_data, 0, swa->buffers[i].buffer_size);
#endif
if (switch_audio_ipc_output_append_buffer(swa, &swa->buffers[i]) != 0)
goto fail_audio_output;
}
compat_mutex_create(&swa->fifoLock);
swa->fifoSize = (swa->sampleRate * sample_size * swa->latency) / 1000;
swa->fifo = fifo_new(swa->fifoSize); swa->fifo = fifo_new(swa->fifoSize);
condvarInit(&swa->cond); compat_condvar_create(&swa->cond);
RARCH_LOG("[Audio]: switch_thread_audio_init device %s requested rate %hu rate %hu latency %hu block_frames %hu fifoSize %lu\n", 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); device, rate, swa->sampleRate, swa->latency, block_frames, swa->fifoSize);
u32 prio; uint32_t prio;
svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); svcGetThreadPriority(&prio, 0xffff8000);
rc = threadCreate(&swa->thread, &mainLoop, (void*)swa, THREAD_STACK_SIZE, prio + 1, AUDIO_THREAD_CPU); rc = compat_thread_create(&swa->thread, &mainLoop, (void*)swa, thread_stack_size, prio + 1, thread_preferred_cpu);
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
@ -181,15 +256,25 @@ static void *switch_thread_audio_init(const char *device, unsigned rate, unsigne
return NULL; return NULL;
} }
if (R_FAILED(threadStart(&swa->thread))) if (R_FAILED(compat_thread_start(&swa->thread)))
{ {
RARCH_LOG("[Audio]: thread creation failed start %u\n", swa->thread.handle); RARCH_LOG("[Audio]: thread creation failed start %u\n", swa->thread.handle);
threadClose(&swa->thread); compat_thread_close(&swa->thread);
swa->running = false; swa->running = false;
return NULL; return NULL;
} }
return swa; return swa;
fail_audio_output:
#ifndef HAVE_LIBNX
audio_ipc_output_close(&swa->output);
#endif
fail_audio_ipc:
switch_audio_ipc_finalize();
fail:
free(swa); // freeing a null ptr is valid
return NULL;
} }
static bool switch_thread_audio_start(void *data, bool is_shutdown) static bool switch_thread_audio_start(void *data, bool is_shutdown)
@ -225,12 +310,12 @@ static void switch_thread_audio_free(void *data)
if (swa->running) if (swa->running)
{ {
swa->running = false; swa->running = false;
threadWaitForExit(&swa->thread); compat_thread_join(&swa->thread);
threadClose(&swa->thread); compat_thread_close(&swa->thread);
} }
audoutStopAudioOut(); switch_audio_ipc_output_stop(swa);
audoutExit(); switch_audio_ipc_finalize();
if (swa->fifo) if (swa->fifo)
{ {
@ -238,8 +323,13 @@ static void switch_thread_audio_free(void *data)
swa->fifo = NULL; swa->fifo = NULL;
} }
for (int i = 0; i < AUDIO_BUFFER_COUNT; i++) for (int i = 0; i < sizeof(swa->buffers)/sizeof(swa->buffers[0]); i++) {
free(swa->buffer[i].buffer); #ifdef HAVE_LIBNX
free(swa->buffers[i].buffer);
#else
free_pages(swa->buffers[i].sample_data);
#endif
}
free(swa); free(swa);
swa = NULL; swa = NULL;
@ -257,35 +347,35 @@ static ssize_t switch_thread_audio_write(void *data, const void *buf, size_t siz
if (swa->nonblocking) if (swa->nonblocking)
{ {
lockMutex(&swa->fifoLock); compat_mutex_lock(&swa->fifoLock);
avail = fifo_write_avail(swa->fifo); avail = fifo_write_avail(swa->fifo);
written = MIN(avail, size); written = MIN(avail, size);
if (written > 0) if (written > 0)
{ {
fifo_write(swa->fifo, buf, written); fifo_write(swa->fifo, buf, written);
} }
mutexUnlock(&swa->fifoLock); compat_mutex_unlock(&swa->fifoLock);
} }
else else
{ {
written = 0; written = 0;
while (written < size && swa->running) while (written < size && swa->running)
{ {
lockMutex(&swa->fifoLock); compat_mutex_lock(&swa->fifoLock);
avail = fifo_write_avail(swa->fifo); avail = fifo_write_avail(swa->fifo);
if (avail == 0) if (avail == 0)
{ {
mutexUnlock(&swa->fifoLock); compat_mutex_unlock(&swa->fifoLock);
lockMutex(&swa->condLock); compat_mutex_lock(&swa->condLock);
if (swa->running) if (swa->running)
condvarWait(&swa->cond, &swa->condLock); compat_condvar_wait(&swa->cond, &swa->condLock);
mutexUnlock(&swa->condLock); compat_mutex_unlock(&swa->condLock);
} }
else else
{ {
size_t write_amt = MIN(size - written, avail); size_t write_amt = MIN(size - written, avail);
fifo_write(swa->fifo, (const char*)buf + written, write_amt); fifo_write(swa->fifo, (const char*)buf + written, write_amt);
mutexUnlock(&swa->fifoLock); compat_mutex_unlock(&swa->fifoLock);
written += write_amt; written += write_amt;
} }
} }
@ -322,9 +412,9 @@ static size_t switch_thread_audio_write_avail(void *data)
{ {
switch_thread_audio_t* swa = (switch_thread_audio_t*)data; switch_thread_audio_t* swa = (switch_thread_audio_t*)data;
lockMutex(&swa->fifoLock); compat_mutex_lock(&swa->fifoLock);
size_t val = fifo_write_avail(swa->fifo); size_t val = fifo_write_avail(swa->fifo);
mutexUnlock(&swa->fifoLock); compat_mutex_unlock(&swa->fifoLock);
return val; return val;
} }

View File

@ -11,7 +11,12 @@
#include <formats/rpng.h> #include <formats/rpng.h>
#include <formats/image.h> #include <formats/image.h>
#ifdef HAVE_LIBNX
#include <switch.h> #include <switch.h>
#else
#include <libtransistor/nx.h>
#include <libtransistor/ipc_helpers.h>
#endif
#include <file/file_path.h> #include <file/file_path.h>
@ -37,17 +42,27 @@
#endif #endif
#endif #endif
#ifdef HAVE_LIBNX
#define SD_PREFIX
#else
#define SD_PREFIX "/sd"
#endif
static enum frontend_fork switch_fork_mode = FRONTEND_FORK_NONE; static enum frontend_fork switch_fork_mode = FRONTEND_FORK_NONE;
static const char *elf_path_cst = "/switch/retroarch_switch.nro"; static const char *elf_path_cst = "/switch/retroarch_switch.nro";
static uint64_t frontend_switch_get_mem_used(void); static uint64_t frontend_switch_get_mem_used(void);
#ifdef HAVE_LIBNX
// Splash // Splash
static uint32_t *splashData = NULL; static uint32_t *splashData = NULL;
// switch_gfx.c protypes, we really need a header // 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); extern void gfx_slow_swizzling_blit(uint32_t *buffer, uint32_t *image, int w, int h, int tx, int ty, bool blend);
#endif // HAVE_LIBNX
static void get_first_valid_core(char *path_return) static void get_first_valid_core(char *path_return)
{ {
DIR *dir; DIR *dir;
@ -56,16 +71,16 @@ static void get_first_valid_core(char *path_return)
path_return[0] = '\0'; path_return[0] = '\0';
dir = opendir("/retroarch/cores"); dir = opendir(SD_PREFIX "/retroarch/cores");
if (dir != NULL) if (dir != NULL)
{ {
while (ent = readdir(dir)) while ((ent = readdir(dir)) != NULL)
{ {
if (ent == NULL) if (ent == NULL)
break; break;
if (strlen(ent->d_name) > strlen(extension) && !strcmp(ent->d_name + strlen(ent->d_name) - strlen(extension), extension)) if (strlen(ent->d_name) > strlen(extension) && !strcmp(ent->d_name + strlen(ent->d_name) - strlen(extension), extension))
{ {
strcpy(path_return, "/retroarch/cores"); strcpy(path_return, SD_PREFIX "/retroarch/cores");
strcat(path_return, "/"); strcat(path_return, "/");
strcat(path_return, ent->d_name); strcat(path_return, ent->d_name);
break; break;
@ -83,11 +98,11 @@ static void frontend_switch_get_environment_settings(int *argc, char *argv[], vo
#if defined(HAVE_LOGGER) #if defined(HAVE_LOGGER)
logger_init(); logger_init();
#elif defined(HAVE_FILE_LOGGER) #elif defined(HAVE_FILE_LOGGER)
retro_main_log_file_init("/retroarch-log.txt"); retro_main_log_file_init(SD_PREFIX "/retroarch-log.txt");
#endif #endif
#endif #endif
fill_pathname_basedir(g_defaults.dirs[DEFAULT_DIR_PORT], "/retroarch/retroarch_switch.nro", sizeof(g_defaults.dirs[DEFAULT_DIR_PORT])); fill_pathname_basedir(g_defaults.dirs[DEFAULT_DIR_PORT], SD_PREFIX "/retroarch/retroarch_switch.nro", sizeof(g_defaults.dirs[DEFAULT_DIR_PORT]));
RARCH_LOG("port dir: [%s]\n", 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], fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], g_defaults.dirs[DEFAULT_DIR_PORT],
@ -137,7 +152,8 @@ static void frontend_switch_deinit(void *data)
{ {
(void)data; (void)data;
#if defined(HAVE_LIBNX) && defined(NXLINK) // Else freeze on exit #ifdef HAVE_LIBNX
#if defined(SWITCH) && defined(NXLINK)
socketExit(); socketExit();
#endif #endif
@ -149,8 +165,10 @@ static void frontend_switch_deinit(void *data)
} }
gfxExit(); gfxExit();
#endif
} }
#ifdef HAVE_LIBNX
static void frontend_switch_exec(const char *path, bool should_load_game) static void frontend_switch_exec(const char *path, bool should_load_game)
{ {
char game_path[PATH_MAX]; char game_path[PATH_MAX];
@ -262,11 +280,6 @@ static void frontend_switch_exitspawn(char *s, size_t len)
frontend_switch_exec(s, should_load_game); 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) void argb_to_rgba8(uint32_t *buff, uint32_t height, uint32_t width)
{ {
// Convert // Convert
@ -418,16 +431,16 @@ char *realpath(const char *name, char *resolved)
if (name == NULL) if (name == NULL)
{ {
/* As per Single Unix Specification V2 we must return an error if /* As per Single Unix Specification V2 we must return an error if
either parameter is a null pointer. We extend this to allow either parameter is a null pointer. We extend this to allow
the RESOLVED parameter to be NULL in case the we are expected to the RESOLVED parameter to be NULL in case the we are expected to
allocate the room for the return value. */ allocate the room for the return value. */
return NULL; return NULL;
} }
if (name[0] == '\0') if (name[0] == '\0')
{ {
/* As per Single Unix Specification V2 we must return an error if /* As per Single Unix Specification V2 we must return an error if
the name argument points to an empty string. */ the name argument points to an empty string. */
return NULL; return NULL;
} }
@ -536,6 +549,13 @@ error:
return NULL; return NULL;
} }
#endif // HAVE_LIBNX
static void frontend_switch_shutdown(bool unused)
{
(void)unused;
}
// runloop_get_system_info isnt initialized that early.. // runloop_get_system_info isnt initialized that early..
extern void retro_get_system_info(struct retro_system_info *info); extern void retro_get_system_info(struct retro_system_info *info);
@ -543,6 +563,7 @@ static void frontend_switch_init(void *data)
{ {
(void)data; (void)data;
#ifdef HAVE_LIBNX // splash
// Init Resolution before initDefault // Init Resolution before initDefault
gfxInitResolution(1280, 720); gfxInitResolution(1280, 720);
@ -551,13 +572,13 @@ static void frontend_switch_init(void *data)
gfxConfigureTransform(0); gfxConfigureTransform(0);
#if defined(HAVE_LIBNX) && defined(NXLINK) #ifdef NXLINK
socketInitializeDefault(); socketInitializeDefault();
nxlinkStdio(); nxlinkStdio();
#ifndef IS_SALAMANDER #ifndef IS_SALAMANDER
verbosity_enable(); verbosity_enable();
#endif #endif
#endif #endif // NXLINK
rarch_system_info_t *sys_info = runloop_get_system_info(); rarch_system_info_t *sys_info = runloop_get_system_info();
retro_get_system_info(sys_info); retro_get_system_info(sys_info);
@ -610,6 +631,7 @@ static void frontend_switch_init(void *data)
{ {
frontend_switch_showsplash(); frontend_switch_showsplash();
} }
#endif // HAVE_LIBNX (splash)
} }
static int frontend_switch_get_rating(void) static int frontend_switch_get_rating(void)
@ -642,7 +664,7 @@ static int frontend_switch_parse_drive_list(void *data, bool load_content)
static uint64_t frontend_switch_get_mem_total(void) static uint64_t frontend_switch_get_mem_total(void)
{ {
uint64_t memoryTotal = 0; uint64_t memoryTotal = 0;
svcGetInfo(&memoryTotal, 6, CUR_PROCESS_HANDLE, 0); // avaiable svcGetInfo(&memoryTotal, 6, 0xffff8001, 0); // avaiable
memoryTotal += frontend_switch_get_mem_used(); memoryTotal += frontend_switch_get_mem_used();
return memoryTotal; return memoryTotal;
@ -651,7 +673,7 @@ static uint64_t frontend_switch_get_mem_total(void)
static uint64_t frontend_switch_get_mem_used(void) static uint64_t frontend_switch_get_mem_used(void)
{ {
uint64_t memoryUsed = 0; uint64_t memoryUsed = 0;
svcGetInfo(&memoryUsed, 7, CUR_PROCESS_HANDLE, 0); // used svcGetInfo(&memoryUsed, 7, 0xffff8001, 0); // used
return memoryUsed; return memoryUsed;
} }
@ -666,6 +688,7 @@ static void frontend_switch_get_os(char *s, size_t len, int *major, int *minor)
{ {
strlcpy(s, "Horizon OS", len); strlcpy(s, "Horizon OS", len);
#ifdef HAVE_LIBNX
// There is pretty sure a better way, but this will do just fine // There is pretty sure a better way, but this will do just fine
if (kernelAbove500()) if (kernelAbove500())
{ {
@ -693,6 +716,37 @@ static void frontend_switch_get_os(char *s, size_t len, int *major, int *minor)
*major = 1; *major = 1;
*minor = 0; *minor = 0;
} }
#else
// defaults in case we error out
*major = 0;
*minor = 0;
char firmware_version[0x100];
result_t r; // used by LIB_ASSERT_OK macros
LIB_ASSERT_OK(fail, sm_init());
ipc_object_t set_sys;
LIB_ASSERT_OK(fail_sm, sm_get_service(&set_sys, "set:sys"));
ipc_request_t rq = ipc_make_request(3);
ipc_buffer_t buffers[] = {
ipc_make_buffer(firmware_version, 0x100, 0x1a),
};
ipc_msg_set_buffers(rq, buffers, buffer_ptrs);
LIB_ASSERT_OK(fail_object, ipc_send(set_sys, &rq, &ipc_default_response_fmt));
int patch;
sscanf(firmware_version + 0x68, "%d.%d.%d", major, minor, &patch);
fail_object:
ipc_close(set_sys);
fail_sm:
sm_finalize();
fail:
return;
#endif
} }
static void frontend_switch_get_name(char *s, size_t len) static void frontend_switch_get_name(char *s, size_t len)
@ -706,6 +760,7 @@ frontend_ctx_driver_t frontend_ctx_switch =
frontend_switch_get_environment_settings, frontend_switch_get_environment_settings,
frontend_switch_init, frontend_switch_init,
frontend_switch_deinit, frontend_switch_deinit,
#ifdef HAVE_LIBNX
frontend_switch_exitspawn, frontend_switch_exitspawn,
NULL, /* process_args */ NULL, /* process_args */
frontend_switch_exec, frontend_switch_exec,
@ -714,6 +769,12 @@ frontend_ctx_driver_t frontend_ctx_switch =
#else #else
frontend_switch_set_fork, frontend_switch_set_fork,
#endif #endif
#else // HAVE_LIBNX
NULL,
NULL,
NULL,
NULL,
#endif // HAVE_LIBNX
frontend_switch_shutdown, frontend_switch_shutdown,
frontend_switch_get_name, frontend_switch_get_name,
frontend_switch_get_os, frontend_switch_get_os,

View File

@ -70,6 +70,9 @@ static frontend_ctx_driver_t *frontend_ctx_drivers[] = {
#endif #endif
#ifdef DJGPP #ifdef DJGPP
&frontend_ctx_dos, &frontend_ctx_dos,
#endif
#ifdef SWITCH
&frontend_ctx_switch,
#endif #endif
&frontend_ctx_null, &frontend_ctx_null,
NULL NULL

View File

@ -126,6 +126,7 @@ extern frontend_ctx_driver_t frontend_ctx_win32;
extern frontend_ctx_driver_t frontend_ctx_xenon; extern frontend_ctx_driver_t frontend_ctx_xenon;
extern frontend_ctx_driver_t frontend_ctx_emscripten; extern frontend_ctx_driver_t frontend_ctx_emscripten;
extern frontend_ctx_driver_t frontend_ctx_dos; extern frontend_ctx_driver_t frontend_ctx_dos;
extern frontend_ctx_driver_t frontend_ctx_switch;
extern frontend_ctx_driver_t frontend_ctx_null; extern frontend_ctx_driver_t frontend_ctx_null;
/** /**

View File

@ -1,5 +1,5 @@
/* RetroArch - A frontend for libretro. /* RetroArch - A frontend for libretro.
* Copyright (C) 2018 - misson2000 * Copyright (C) 2018 - misson20000
* Copyright (C) 2018 - m4xw * Copyright (C) 2018 - m4xw
* *
* RetroArch is free software: you can redistribute it and/or modify it under the terms * RetroArch is free software: you can redistribute it and/or modify it under the terms

View File

@ -1,5 +1,5 @@
/* RetroArch - A frontend for libretro. /* RetroArch - A frontend for libretro.
* Copyright (C) 2018 - misson2000 * Copyright (C) 2018 - misson20000
* Copyright (C) 2018 - m4xw * Copyright (C) 2018 - m4xw
* *
* RetroArch is free software: you can redistribute it and/or modify it under the terms * RetroArch is free software: you can redistribute it and/or modify it under the terms

View File

@ -391,7 +391,7 @@ int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, i
#ifdef _WIN32 #ifdef _WIN32
if(_chsize(_fileno(stream->fp), length) != 0) if(_chsize(_fileno(stream->fp), length) != 0)
return -1; return -1;
#elif !defined(VITA) && !defined(PSP) #elif !defined(VITA) && !defined(PSP) && (!defined(SWITCH) || defined(HAVE_LIBNX))
if(ftruncate(fileno(stream->fp), length) != 0) if(ftruncate(fileno(stream->fp), length) != 0)
return -1; return -1;
#endif #endif