mirror of
https://github.com/libretro/libretro-common.git
synced 2024-11-23 08:09:43 +00:00
Updates
This commit is contained in:
parent
0674aa29f6
commit
11ce906571
@ -177,17 +177,18 @@ struct audio_mixer_voice
|
||||
#ifdef HAVE_IBXM
|
||||
struct
|
||||
{
|
||||
unsigned position;
|
||||
unsigned samples;
|
||||
unsigned buf_samples;
|
||||
int* buffer;
|
||||
struct replay* stream;
|
||||
unsigned position;
|
||||
unsigned samples;
|
||||
unsigned buf_samples;
|
||||
int* buffer;
|
||||
struct replay* stream;
|
||||
struct module* module;
|
||||
} mod;
|
||||
#endif
|
||||
} types;
|
||||
};
|
||||
|
||||
static struct audio_mixer_voice s_voices[AUDIO_MIXER_MAX_VOICES];
|
||||
static struct audio_mixer_voice s_voices[AUDIO_MIXER_MAX_VOICES] = {{0}};
|
||||
static unsigned s_rate = 0;
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
@ -317,6 +318,8 @@ void audio_mixer_init(unsigned rate)
|
||||
s_voices[i].type = AUDIO_MIXER_TYPE_NONE;
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
if (s_locker)
|
||||
slock_free(s_locker);
|
||||
s_locker = slock_new();
|
||||
#endif
|
||||
}
|
||||
@ -550,10 +553,19 @@ static bool audio_mixer_play_ogg(
|
||||
|
||||
if (!ogg_buffer)
|
||||
{
|
||||
resamp->free(resampler_data);
|
||||
if (resamp && resampler_data)
|
||||
resamp->free(resampler_data);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* "system" menu sounds may reuse the same voice without freeing anything first, so do that here if needed */
|
||||
if (voice->types.ogg.stream)
|
||||
stb_vorbis_close(voice->types.ogg.stream);
|
||||
if (voice->types.ogg.resampler && voice->types.ogg.resampler_data)
|
||||
voice->types.ogg.resampler->free(voice->types.ogg.resampler_data);
|
||||
if (voice->types.ogg.buffer)
|
||||
memalign_free(voice->types.ogg.buffer);
|
||||
|
||||
voice->types.ogg.resampler = resamp;
|
||||
voice->types.ogg.resampler_data = resampler_data;
|
||||
voice->types.ogg.buffer = (float*)ogg_buffer;
|
||||
@ -596,7 +608,12 @@ static bool audio_mixer_play_mod(
|
||||
goto error;
|
||||
}
|
||||
|
||||
replay = new_replay( module, s_rate, 1);
|
||||
if (voice->types.mod.module)
|
||||
dispose_module(voice->types.mod.module);
|
||||
|
||||
voice->types.mod.module = module;
|
||||
|
||||
replay = new_replay(module, s_rate, 1);
|
||||
|
||||
if (!replay)
|
||||
{
|
||||
@ -621,11 +638,17 @@ static bool audio_mixer_play_mod(
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* FIXME: stopping and then starting a mod stream will crash here in dispose_replay (ASAN says struct replay is misaligned?) */
|
||||
if (voice->types.mod.stream)
|
||||
dispose_replay(voice->types.mod.stream);
|
||||
if (voice->types.mod.buffer)
|
||||
memalign_free(voice->types.mod.buffer);
|
||||
|
||||
voice->types.mod.buffer = (int*)mod_buffer;
|
||||
voice->types.mod.buf_samples = buf_samples;
|
||||
voice->types.mod.stream = replay;
|
||||
voice->types.mod.position = 0;
|
||||
voice->types.mod.samples = 0; /* samples; */
|
||||
voice->types.mod.samples = 0; /* samples; */
|
||||
|
||||
return true;
|
||||
|
||||
@ -677,6 +700,13 @@ static bool audio_mixer_play_flac(
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (voice->types.flac.stream)
|
||||
drflac_close(voice->types.flac.stream);
|
||||
if (voice->types.flac.resampler && voice->types.flac.resampler_data)
|
||||
voice->types.flac.resampler->free(voice->types.flac.resampler_data);
|
||||
if (voice->types.flac.buffer)
|
||||
memalign_free(voice->types.flac.buffer);
|
||||
|
||||
voice->types.flac.resampler = resamp;
|
||||
voice->types.flac.resampler_data = resampler_data;
|
||||
voice->types.flac.buffer = (float*)flac_buffer;
|
||||
@ -706,9 +736,19 @@ static bool audio_mixer_play_mp3(
|
||||
void *mp3_buffer = NULL;
|
||||
void *resampler_data = NULL;
|
||||
const retro_resampler_t* resamp = NULL;
|
||||
bool res =drmp3_init_memory(&voice->types.mp3.stream,(const unsigned char*)sound->types.mp3.data,sound->types.mp3.size,NULL);
|
||||
bool res;
|
||||
|
||||
if (voice->types.mp3.stream.pData)
|
||||
{
|
||||
drmp3_uninit(&voice->types.mp3.stream);
|
||||
memset(&voice->types.mp3.stream, 0, sizeof(voice->types.mp3.stream));
|
||||
}
|
||||
|
||||
res = drmp3_init_memory(&voice->types.mp3.stream, (const unsigned char*)sound->types.mp3.data, sound->types.mp3.size, NULL);
|
||||
|
||||
if (!res)
|
||||
return false;
|
||||
|
||||
if (voice->types.mp3.stream.sampleRate != s_rate)
|
||||
{
|
||||
ratio = (double)s_rate / (double)(voice->types.mp3.stream.sampleRate);
|
||||
@ -725,10 +765,17 @@ static bool audio_mixer_play_mp3(
|
||||
|
||||
if (!mp3_buffer)
|
||||
{
|
||||
resamp->free(resampler_data);
|
||||
if (resamp && resampler_data)
|
||||
resamp->free(resampler_data);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* "system" menu sounds may reuse the same voice without freeing anything first, so do that here if needed */
|
||||
if (voice->types.mp3.resampler && voice->types.mp3.resampler_data)
|
||||
voice->types.mp3.resampler->free(voice->types.mp3.resampler_data);
|
||||
if (voice->types.mp3.buffer)
|
||||
memalign_free(voice->types.mp3.buffer);
|
||||
|
||||
voice->types.mp3.resampler = resamp;
|
||||
voice->types.mp3.resampler_data = resampler_data;
|
||||
voice->types.mp3.buffer = (float*)mp3_buffer;
|
||||
@ -759,6 +806,8 @@ audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat,
|
||||
slock_lock(s_locker);
|
||||
#endif
|
||||
|
||||
audio_resampler_lock();
|
||||
|
||||
for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++, voice++)
|
||||
{
|
||||
if (voice->type != AUDIO_MIXER_TYPE_NONE)
|
||||
@ -807,6 +856,8 @@ audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat,
|
||||
else
|
||||
voice = NULL;
|
||||
|
||||
audio_resampler_unlock();
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
slock_unlock(s_locker);
|
||||
#endif
|
||||
@ -821,13 +872,13 @@ void audio_mixer_stop(audio_mixer_voice_t* voice)
|
||||
|
||||
if (voice)
|
||||
{
|
||||
stop_cb = voice->stop_cb;
|
||||
sound = voice->sound;
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
slock_lock(s_locker);
|
||||
#endif
|
||||
|
||||
stop_cb = voice->stop_cb;
|
||||
sound = voice->sound;
|
||||
|
||||
voice->type = AUDIO_MIXER_TYPE_NONE;
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
@ -929,7 +980,9 @@ again:
|
||||
info.ratio = voice->types.ogg.ratio;
|
||||
|
||||
if (voice->types.ogg.resampler)
|
||||
{
|
||||
voice->types.ogg.resampler->process(voice->types.ogg.resampler_data, &info);
|
||||
}
|
||||
else
|
||||
memcpy(voice->types.ogg.buffer, temp_buffer, temp_samples * sizeof(float));
|
||||
voice->types.ogg.position = 0;
|
||||
@ -1076,7 +1129,9 @@ again:
|
||||
info.ratio = voice->types.flac.ratio;
|
||||
|
||||
if (voice->types.flac.resampler)
|
||||
{
|
||||
voice->types.flac.resampler->process(voice->types.flac.resampler_data, &info);
|
||||
}
|
||||
else
|
||||
memcpy(voice->types.flac.buffer, temp_buffer, temp_samples * sizeof(float));
|
||||
voice->types.flac.position = 0;
|
||||
@ -1189,6 +1244,8 @@ void audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bo
|
||||
slock_lock(s_locker);
|
||||
#endif
|
||||
|
||||
audio_resampler_lock();
|
||||
|
||||
for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++, voice++)
|
||||
{
|
||||
float volume = (override) ? volume_override : voice->volume;
|
||||
@ -1223,10 +1280,6 @@ void audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bo
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
slock_unlock(s_locker);
|
||||
#endif
|
||||
|
||||
for (j = 0, sample = buffer; j < num_frames; j++, sample++)
|
||||
{
|
||||
if (*sample < -1.0f)
|
||||
@ -1234,6 +1287,12 @@ void audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bo
|
||||
else if (*sample > 1.0f)
|
||||
*sample = 1.0f;
|
||||
}
|
||||
|
||||
audio_resampler_unlock();
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
slock_unlock(s_locker);
|
||||
#endif
|
||||
}
|
||||
|
||||
float audio_mixer_voice_get_volume(audio_mixer_voice_t *voice)
|
||||
|
@ -9,4 +9,3 @@ iir_frequency = 200.0
|
||||
# Avoids clipping.
|
||||
panning_left_mix = "0.3 0.0"
|
||||
panning_right_mix = "0.0 0.3"
|
||||
|
||||
|
@ -4,4 +4,3 @@ filter0 = iir
|
||||
iir_gain = -12.0
|
||||
iir_type = HSH
|
||||
iir_frequency = 8000.0
|
||||
|
||||
|
@ -20,4 +20,3 @@ filter0 = iir
|
||||
# LSH: Low-shelf
|
||||
# HSH: High-shelf
|
||||
# RIAA_CD: CD de-emphasis
|
||||
|
||||
|
@ -20,4 +20,3 @@ panning_right_mix = "0.0 1.0"
|
||||
# Mono on one speaker:
|
||||
# panning_left_mix = "0.5 0.5"
|
||||
# panning_right_mix = "0.0 0.0"
|
||||
|
||||
|
@ -8,4 +8,3 @@ filter0 = phaser
|
||||
# phaser_depth = 0.4
|
||||
# phaser_dry_wet = 0.5
|
||||
# phaser_stages = 2
|
||||
|
||||
|
@ -7,4 +7,3 @@ filter0 = reverb
|
||||
# reverb_damping = 0.8
|
||||
# reverb_roomwidth = 0.56
|
||||
# reverb_roomsize = 0.56
|
||||
|
||||
|
@ -4,4 +4,3 @@ filter0 = tremolo
|
||||
# Defaults.
|
||||
#tremolo_frequency = 4.0
|
||||
#tremolo_depth = 0.9
|
||||
|
||||
|
@ -4,4 +4,3 @@ filter0 = vibrato
|
||||
# Defaults.
|
||||
#vibrato_frequency = 5.0
|
||||
#vibrato_depth = 0.5
|
||||
|
||||
|
@ -7,4 +7,3 @@ filter0 = wahwah
|
||||
# wahwah_freq_offset = 0.3
|
||||
# wahwah_depth = 0.7
|
||||
# wahwah_resonance = 2.5
|
||||
|
||||
|
@ -158,4 +158,3 @@ dspfilter_get_implementation(dspfilter_simd_mask_t mask)
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
|
@ -88,4 +88,3 @@ const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_si
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
|
@ -178,4 +178,3 @@ const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_si
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
|
@ -348,4 +348,3 @@ const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_si
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
|
@ -202,4 +202,3 @@ void fft_process_inverse(fft_t *fft,
|
||||
|
||||
resolve_float(out, fft->interleave_buffer, samples, 1.0f / samples, step);
|
||||
}
|
||||
|
||||
|
@ -42,4 +42,3 @@ void fft_process_inverse(fft_t *fft,
|
||||
float *out, const fft_complex_t *in, unsigned step);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -368,4 +368,3 @@ const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_si
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
|
@ -109,4 +109,3 @@ dspfilter_get_implementation(dspfilter_simd_mask_t mask)
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
|
@ -143,4 +143,3 @@ const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_si
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
|
@ -314,4 +314,3 @@ const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_si
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
|
@ -130,4 +130,3 @@ const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_si
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
|
@ -165,4 +165,3 @@ const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_si
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
|
@ -145,4 +145,3 @@ dspfilter_get_implementation(dspfilter_simd_mask_t mask)
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
|
@ -28,6 +28,14 @@
|
||||
|
||||
#include <audio/audio_resampler.h>
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
#include <rthreads/rthreads.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
static slock_t* s_resampler_lock = NULL;
|
||||
#endif
|
||||
|
||||
static const retro_resampler_t *resampler_drivers[] = {
|
||||
&sinc_resampler,
|
||||
#ifdef HAVE_CC_RESAMPLER
|
||||
@ -170,3 +178,38 @@ bool retro_resampler_realloc(void **re, const retro_resampler_t **backend,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void audio_resampler_lock_init(void)
|
||||
{
|
||||
#ifdef HAVE_THREADS
|
||||
if (s_resampler_lock)
|
||||
slock_free(s_resampler_lock);
|
||||
s_resampler_lock = slock_new();
|
||||
#endif
|
||||
}
|
||||
|
||||
void audio_resampler_lock_free(void)
|
||||
{
|
||||
#ifdef HAVE_THREADS
|
||||
if (s_resampler_lock)
|
||||
slock_free(s_resampler_lock);
|
||||
s_resampler_lock = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void audio_resampler_lock(void)
|
||||
{
|
||||
#ifdef HAVE_THREADS
|
||||
if (s_resampler_lock)
|
||||
slock_lock(s_resampler_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void audio_resampler_unlock(void)
|
||||
{
|
||||
#ifdef HAVE_THREADS
|
||||
if (s_resampler_lock)
|
||||
slock_unlock(s_resampler_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -240,12 +240,20 @@ static int zip_file_read(
|
||||
const char *needle, void **buf,
|
||||
const char *optional_outfile)
|
||||
{
|
||||
file_archive_transfer_t zlib = {0};
|
||||
file_archive_transfer_t zlib;
|
||||
struct archive_extract_userdata userdata = {{0}};
|
||||
bool returnerr = true;
|
||||
int ret = 0;
|
||||
|
||||
zlib.type = ARCHIVE_TRANSFER_INIT;
|
||||
zlib.archive_size = 0;
|
||||
zlib.start_delta = 0;
|
||||
zlib.handle = NULL;
|
||||
zlib.stream = NULL;
|
||||
zlib.footer = NULL;
|
||||
zlib.directory = NULL;
|
||||
zlib.data = NULL;
|
||||
zlib.backend = NULL;
|
||||
|
||||
userdata.decomp_state.needle = NULL;
|
||||
userdata.decomp_state.opt_file = NULL;
|
||||
|
296
file/nbio/nbio_orbis.c
Normal file
296
file/nbio/nbio_orbis.c
Normal file
@ -0,0 +1,296 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (nbio_orbis.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <file/nbio.h>
|
||||
|
||||
#if defined(ORBIS)
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <orbisFile.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
||||
struct nbio_orbis_t
|
||||
{
|
||||
int fd;
|
||||
void* data;
|
||||
size_t progress;
|
||||
size_t len;
|
||||
/*
|
||||
* possible values:
|
||||
* NBIO_READ, NBIO_WRITE - obvious
|
||||
* -1 - currently doing nothing
|
||||
* -2 - the pointer was reallocated since the last operation
|
||||
*/
|
||||
signed char op;
|
||||
unsigned int mode;
|
||||
};
|
||||
|
||||
static void *nbio_orbis_open(const char * filename, unsigned int mode)
|
||||
{
|
||||
static const int o_flags[] = { O_RDONLY, O_RDWR | O_CREAT | O_TRUNC,
|
||||
O_RDWR, O_RDONLY, O_RDWR | O_CREAT | O_TRUNC };
|
||||
void *buf = NULL;
|
||||
struct nbio_orbis_t* handle = NULL;
|
||||
size_t len = 0;
|
||||
int fd = orbisOpen(filename, o_flags[mode], 0644);
|
||||
|
||||
RARCH_LOG("[NBIO_ORBIS] open %s\n" , filename);
|
||||
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
handle = (struct nbio_orbis_t*)malloc(sizeof(struct nbio_orbis_t));
|
||||
|
||||
|
||||
if (!handle)
|
||||
goto error;
|
||||
|
||||
handle->fd = fd;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case NBIO_WRITE:
|
||||
case BIO_WRITE:
|
||||
break;
|
||||
default:
|
||||
len=orbisLseek(handle->fd, 0, SEEK_END);
|
||||
orbisLseek(handle->fd, 0, SEEK_SET);
|
||||
break;
|
||||
}
|
||||
|
||||
handle->mode = mode;
|
||||
|
||||
if (len)
|
||||
buf = malloc(len);
|
||||
|
||||
if (!buf)
|
||||
{
|
||||
RARCH_LOG("[NBIO_ORBIS] open error malloc %d bytes\n",len);
|
||||
}
|
||||
|
||||
if (len && !buf)
|
||||
goto error;
|
||||
|
||||
handle->data = buf;
|
||||
handle->len = len;
|
||||
handle->progress = handle->len;
|
||||
handle->op = -2;
|
||||
|
||||
return handle;
|
||||
|
||||
error:
|
||||
if (handle)
|
||||
free(handle);
|
||||
RARCH_LOG("[NBIO_ORBIS] open error closing %s\n" , filename);
|
||||
orbisClose(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void nbio_orbis_begin_read(void *data)
|
||||
{
|
||||
|
||||
struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
|
||||
if (!handle)
|
||||
return;
|
||||
RARCH_LOG("[NBIO_ORBIS] begin read fd=%d\n", handle->fd );
|
||||
|
||||
if (handle->op >= 0)
|
||||
{
|
||||
RARCH_LOG("[NBIO_ORBIS] ERROR - attempted file read operation while busy\n");
|
||||
return;
|
||||
}
|
||||
|
||||
orbisLseek(handle->fd, 0, SEEK_SET);
|
||||
|
||||
handle->op = NBIO_READ;
|
||||
handle->progress = 0;
|
||||
}
|
||||
|
||||
static void nbio_orbis_begin_write(void *data)
|
||||
{
|
||||
struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
|
||||
if (!handle)
|
||||
return;
|
||||
RARCH_LOG("[NBIO_ORBIS] begin write fd=%d\n", handle->fd );
|
||||
|
||||
if (handle->op >= 0)
|
||||
{
|
||||
RARCH_LOG("[NBIO_ORBIS] ERROR - attempted file write operation while busy\n");
|
||||
return;
|
||||
}
|
||||
|
||||
orbisLseek(handle->fd, 0, SEEK_SET);
|
||||
handle->op = NBIO_WRITE;
|
||||
handle->progress = 0;
|
||||
}
|
||||
|
||||
static bool nbio_orbis_iterate(void *data)
|
||||
{
|
||||
size_t amount = 65536;
|
||||
struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
|
||||
|
||||
if (!handle)
|
||||
return false;
|
||||
RARCH_LOG("[NBIO_ORBIS] begin iterate fd=%d\n", handle->fd );
|
||||
|
||||
if (amount > handle->len - handle->progress)
|
||||
amount = handle->len - handle->progress;
|
||||
|
||||
switch (handle->op)
|
||||
{
|
||||
case NBIO_READ:
|
||||
if (handle->mode == BIO_READ)
|
||||
{
|
||||
amount = handle->len;
|
||||
RARCH_LOG("[NBIO_ORBIS] iterate BIO_READ fd=%d readbytes=%d\n", handle->fd, orbisRead(handle->fd, (char*)handle->data, amount));
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
RARCH_LOG("[NBIO_ORBIS] iterate read fd=%d handle->progress=%d readbytes=%d\n", handle->fd, handle->progress, orbisRead(handle->fd, (char*)handle->data + handle->progress, amount));
|
||||
|
||||
}
|
||||
break;
|
||||
case NBIO_WRITE:
|
||||
if (handle->mode == BIO_WRITE)
|
||||
{
|
||||
size_t written = 0;
|
||||
amount = handle->len;
|
||||
written = orbisWrite(handle->fd, (char*)handle->data, amount);
|
||||
RARCH_LOG("[NBIO_ORBIS] iterate BIO_WRITE fd=%d writebytes=%d\n", handle->fd, written);
|
||||
|
||||
if (written != amount)
|
||||
{
|
||||
RARCH_LOG("[NBIO_ORBIS] iterate BIO_WRITE error fd=%d amount=%d != writebytes=%d\n", handle->fd, amount, written);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RARCH_LOG("[NBIO_ORBIS] iterate write fd=%d writebytes=%d\n", handle->fd, orbisWrite(handle->fd, (char*)handle->data + handle->progress, amount));
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
handle->progress += amount;
|
||||
RARCH_LOG("[NBIO_ORBIS] end iterate fd=%d\n", handle->fd );
|
||||
|
||||
if (handle->progress == handle->len)
|
||||
handle->op = -1;
|
||||
return (handle->op < 0);
|
||||
}
|
||||
|
||||
static void nbio_orbis_resize(void *data, size_t len)
|
||||
{
|
||||
struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
if (handle->op >= 0)
|
||||
{
|
||||
RARCH_LOG("[NBIO_ORBIS] ERROR - attempted file resize operation while busy\n");
|
||||
return;
|
||||
}
|
||||
if (len < handle->len)
|
||||
{
|
||||
RARCH_LOG("[NBIO_ORBIS] ERROR - attempted file shrink operation, not implemented");
|
||||
return;
|
||||
}
|
||||
|
||||
handle->len = len;
|
||||
handle->data = realloc(handle->data, handle->len);
|
||||
handle->op = -1;
|
||||
handle->progress = handle->len;
|
||||
}
|
||||
|
||||
static void *nbio_orbis_get_ptr(void *data, size_t* len)
|
||||
{
|
||||
struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
|
||||
if (!handle)
|
||||
return NULL;
|
||||
RARCH_LOG("[NBIO_ORBIS] get pointer\n");
|
||||
if (len)
|
||||
*len = handle->len;
|
||||
if (handle->op == -1)
|
||||
return handle->data;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void nbio_orbis_cancel(void *data)
|
||||
{
|
||||
struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
|
||||
if (!handle)
|
||||
return;
|
||||
RARCH_LOG("[NBIO_ORBIS] cancel \n");
|
||||
handle->op = -1;
|
||||
handle->progress = handle->len;
|
||||
}
|
||||
|
||||
static void nbio_orbis_free(void *data)
|
||||
{
|
||||
struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
|
||||
if (!handle)
|
||||
return;
|
||||
RARCH_LOG("[NBIO_ORBIS] begin free fd=%d\n", handle->fd );
|
||||
|
||||
if (handle->op >= 0)
|
||||
{
|
||||
RARCH_LOG("[NBIO_ORBIS] ERROR - attempted free() while busy\n");
|
||||
return;
|
||||
}
|
||||
RARCH_LOG("[NBIO_ORBIS] free close fd=%d\n",handle->fd);
|
||||
|
||||
orbisClose(handle->fd);
|
||||
free(handle->data);
|
||||
|
||||
handle->data = NULL;
|
||||
free(handle);
|
||||
}
|
||||
|
||||
nbio_intf_t nbio_orbis = {
|
||||
nbio_orbis_open,
|
||||
nbio_orbis_begin_read,
|
||||
nbio_orbis_begin_write,
|
||||
nbio_orbis_iterate,
|
||||
nbio_orbis_resize,
|
||||
nbio_orbis_get_ptr,
|
||||
nbio_orbis_cancel,
|
||||
nbio_orbis_free,
|
||||
"nbio_orbis",
|
||||
};
|
||||
#else
|
||||
nbio_intf_t nbio_orbis = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"nbio_orbis",
|
||||
};
|
||||
#endif
|
@ -352,4 +352,3 @@ chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t comple
|
||||
}
|
||||
return CHDERR_NONE;
|
||||
}
|
||||
|
||||
|
@ -485,4 +485,3 @@ char *rxml_node_attrib(struct rxml_node *node, const char *attrib)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -24,4 +24,3 @@ clean:
|
||||
rm -f $(TARGET) $(OBJS)
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
|
@ -64,4 +64,3 @@ int main(int argc, char *argv[])
|
||||
|
||||
rxml_log_document(argv[1]);
|
||||
}
|
||||
|
||||
|
68
gfx/scaler/pixconv.Tdepend
Normal file
68
gfx/scaler/pixconv.Tdepend
Normal file
@ -0,0 +1,68 @@
|
||||
libretro-common/gfx/scaler/pixconv.o: \
|
||||
libretro-common/gfx/scaler/pixconv.c \
|
||||
/mnt/d/libretro-super/ps4sdk/include/stdio.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/cdefs.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/_null.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/_types.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/machine/_types.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/stdint.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/machine/_stdint.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/_stdint.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/stdlib.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/string.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/strings.h \
|
||||
libretro-common/include/retro_inline.h \
|
||||
libretro-common/include/gfx/scaler/pixconv.h \
|
||||
libretro-common/include/clamping.h \
|
||||
libretro-common/include/retro_common_api.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/inttypes.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/machine/_inttypes.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/x86/_inttypes.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/stdint.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/emmintrin.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/xmmintrin.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/mmintrin.h
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/stdio.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/cdefs.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/_null.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/_types.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/machine/_types.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/stdint.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/machine/_stdint.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/_stdint.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/stdlib.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/string.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/strings.h:
|
||||
|
||||
libretro-common/include/retro_inline.h:
|
||||
|
||||
libretro-common/include/gfx/scaler/pixconv.h:
|
||||
|
||||
libretro-common/include/clamping.h:
|
||||
|
||||
libretro-common/include/retro_common_api.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/inttypes.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/machine/_inttypes.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/x86/_inttypes.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/stdint.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/emmintrin.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/xmmintrin.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/mmintrin.h:
|
@ -873,4 +873,3 @@ void conv_copy(void *output_, const void *input_,
|
||||
h++, output += out_stride, input += in_stride)
|
||||
memcpy(output, input, copy_len);
|
||||
}
|
||||
|
||||
|
@ -240,4 +240,3 @@ bool scaler_gen_filter(struct scaler_ctx *ctx)
|
||||
|
||||
return validate_filter(ctx);
|
||||
}
|
||||
|
||||
|
68
gfx/scaler/scaler_int.Tdepend
Normal file
68
gfx/scaler/scaler_int.Tdepend
Normal file
@ -0,0 +1,68 @@
|
||||
libretro-common/gfx/scaler/scaler_int.o: \
|
||||
libretro-common/gfx/scaler/scaler_int.c \
|
||||
libretro-common/include/gfx/scaler/scaler_int.h \
|
||||
libretro-common/include/gfx/scaler/scaler.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/stdint.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/cdefs.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/_types.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/machine/_types.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/machine/_stdint.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/_stdint.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/stddef.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/_null.h \
|
||||
libretro-common/include/boolean.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/stdbool.h \
|
||||
libretro-common/include/clamping.h \
|
||||
libretro-common/include/retro_inline.h \
|
||||
libretro-common/include/retro_common_api.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/inttypes.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/machine/_inttypes.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/x86/_inttypes.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/stdint.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/emmintrin.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/xmmintrin.h \
|
||||
/mnt/d/libretro-super/ps4sdk/include/mmintrin.h
|
||||
|
||||
libretro-common/include/gfx/scaler/scaler_int.h:
|
||||
|
||||
libretro-common/include/gfx/scaler/scaler.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/stdint.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/cdefs.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/_types.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/machine/_types.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/machine/_stdint.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/_stdint.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/stddef.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/_null.h:
|
||||
|
||||
libretro-common/include/boolean.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/stdbool.h:
|
||||
|
||||
libretro-common/include/clamping.h:
|
||||
|
||||
libretro-common/include/retro_inline.h:
|
||||
|
||||
libretro-common/include/retro_common_api.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/inttypes.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/machine/_inttypes.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/x86/_inttypes.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/sys/stdint.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/emmintrin.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/xmmintrin.h:
|
||||
|
||||
/mnt/d/libretro-super/ps4sdk/include/mmintrin.h:
|
@ -258,4 +258,3 @@ void scaler_argb8888_point_special(const struct scaler_ctx *ctx,
|
||||
output[w] = inp[x >> 16];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,4 +9,3 @@ Use Khronos' recent [header](www.opengl.org/registry/api/glext.h).
|
||||
## OpenGL ES
|
||||
|
||||
./glgen.py /usr/include/GLES2/gl2ext.h glsym_es2.h glsym_es2.c
|
||||
|
||||
|
@ -155,4 +155,3 @@ if __name__ == '__main__':
|
||||
f.write(' { NULL, NULL },\n')
|
||||
f.write('};\n')
|
||||
dump(f, declarations)
|
||||
|
||||
|
@ -407,4 +407,3 @@ RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
|
||||
RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
|
||||
RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
|
||||
RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;
|
||||
|
||||
|
@ -411,4 +411,3 @@ RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
|
||||
RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
|
||||
RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
|
||||
RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;
|
||||
|
||||
|
@ -2539,4 +2539,3 @@ RGLSYMGLIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glImageTransformParameterivHP;
|
||||
RGLSYMGLIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glImageTransformParameterfvHP;
|
||||
RGLSYMGLGETIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glGetImageTransformParameterivHP;
|
||||
RGLSYMGLGETIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glGetImageTransformParameterfvHP;
|
||||
|
||||
|
@ -38,6 +38,8 @@ void rglgen_resolve_symbols_custom(rglgen_proc_address_t proc,
|
||||
|
||||
void rglgen_resolve_symbols(rglgen_proc_address_t proc)
|
||||
{
|
||||
if (!proc)
|
||||
return;
|
||||
|
||||
rglgen_resolve_symbols_custom(proc, rglgen_symbol_map);
|
||||
}
|
||||
|
||||
|
@ -147,5 +147,3 @@ if __name__ == '__main__':
|
||||
f.write(' { NULL, NULL },\n')
|
||||
f.write('};\n')
|
||||
dump(f, declarations)
|
||||
|
||||
|
||||
|
@ -156,4 +156,3 @@ if __name__ == '__main__':
|
||||
f.write(' { NULL, NULL },\n')
|
||||
f.write('};\n')
|
||||
dump(f, declarations)
|
||||
|
||||
|
1003
include/array/dynarray.h
Normal file
1003
include/array/dynarray.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -190,6 +190,14 @@ const char *audio_resampler_driver_find_ident(int index);
|
||||
bool retro_resampler_realloc(void **re, const retro_resampler_t **backend,
|
||||
const char *ident, enum resampler_quality quality, double bw_ratio);
|
||||
|
||||
void audio_resampler_lock_init(void);
|
||||
|
||||
void audio_resampler_lock(void);
|
||||
|
||||
void audio_resampler_unlock(void);
|
||||
|
||||
void audio_resampler_lock_free(void);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
@ -50,4 +50,3 @@ void retro_dsp_filter_process(retro_dsp_filter_t *dsp,
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -72,4 +72,3 @@ RETRO_END_DECLS
|
||||
|
||||
/* pragma once */
|
||||
#endif
|
||||
|
||||
|
@ -125,4 +125,3 @@ typedef int ssize_t;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -253,4 +253,3 @@ typedef uint64_t uintmax_t;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -50,4 +50,3 @@ RETRO_END_DECLS
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -57,4 +57,3 @@ char *strldup(const char *s, size_t n);
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -214,4 +214,3 @@ extern const struct file_archive_file_backend sevenzip_backend;
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -46,4 +46,3 @@ rjpeg_t *rjpeg_alloc(void);
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -59,4 +59,3 @@ bool rpng_save_image_bgr24(const char *path, const uint8_t *data,
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -92,4 +92,3 @@ typedef rxml_document_t *xmlDocPtr;
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -393,4 +393,3 @@ typedef struct math_matrix_4x4
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -136,4 +136,3 @@ static INLINE unsigned int vec2_packHalf2x16(float vec0, float vec1)
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -66,4 +66,3 @@ typedef float vec3_t[3];
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -59,4 +59,3 @@ typedef float vec4_t[4];
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -35,4 +35,3 @@ bool scaler_gen_filter(struct scaler_ctx *ctx);
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -100,4 +100,3 @@ void conv_copy(void *output, const void *input,
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -126,4 +126,3 @@ void scaler_ctx_scale(struct scaler_ctx *ctx,
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -44,4 +44,3 @@ void scaler_argb8888_point_special(const struct scaler_ctx *ctx,
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -39,4 +39,3 @@
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -44,4 +44,3 @@ void rglgen_resolve_symbols_custom(rglgen_proc_address_t proc,
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -39,8 +39,14 @@
|
||||
#endif
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#include <compat/apple_compat.h>
|
||||
#if MAC_OS_X_VERSION_10_7
|
||||
#include <OpenGL/gl3.h>
|
||||
#include <OpenGL/gl3ext.h>
|
||||
#else
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glext.h>
|
||||
#endif
|
||||
#elif defined(HAVE_PSGL)
|
||||
#include <PSGL/psgl.h>
|
||||
#include <GLES/glext.h>
|
||||
@ -84,4 +90,12 @@
|
||||
#define GL_RED_INTEGER 0x8D94
|
||||
#endif
|
||||
|
||||
#ifndef GL_BGRA_EXT
|
||||
#define GL_BGRA_EXT GL_BGRA
|
||||
#endif
|
||||
|
||||
#ifndef GL_LUMINANCE_ALPHA
|
||||
#define GL_LUMINANCE_ALPHA 0x190A
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1258,6 +1258,7 @@ enum retro_hw_render_interface_type
|
||||
RETRO_HW_RENDER_INTERFACE_D3D10 = 2,
|
||||
RETRO_HW_RENDER_INTERFACE_D3D11 = 3,
|
||||
RETRO_HW_RENDER_INTERFACE_D3D12 = 4,
|
||||
RETRO_HW_RENDER_INTERFACE_GSKIT_PS2 = 5,
|
||||
RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX
|
||||
};
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
#ifdef HAVE_D3D11
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <D3Dcompiler.h>
|
||||
#include <d3dcompiler.h>
|
||||
|
||||
#define RETRO_HW_RENDER_INTERFACE_D3D11_VERSION 1
|
||||
|
||||
|
56
include/libretro_gskit_ps2.h
Normal file
56
include/libretro_gskit_ps2.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this libretro API header (libretro_d3d.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 LIBRETRO_GSKIT_PS2_H_
|
||||
#define LIBRETRO_GSKIT_PS2_H_
|
||||
|
||||
#include "libretro.h"
|
||||
|
||||
#if defined(PS2)
|
||||
|
||||
#include <gsKit.h>
|
||||
|
||||
#define RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION 1
|
||||
|
||||
struct retro_hw_render_interface_gskit_ps2
|
||||
{
|
||||
/* Must be set to RETRO_HW_RENDER_INTERFACE_GSKIT_PS2. */
|
||||
enum retro_hw_render_interface_type interface_type;
|
||||
/* Must be set to RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION. */
|
||||
unsigned interface_version;
|
||||
|
||||
/* Opaque handle to the GSKit_PS2 backend in the frontend
|
||||
* which must be passed along to all function pointers
|
||||
* in this interface.
|
||||
*/
|
||||
GSTEXTURE *coreTexture;
|
||||
bool clearTexture;
|
||||
};
|
||||
typedef struct retro_hw_render_interface_gskit_ps2 RETRO_HW_RENDER_INTEFACE_GSKIT_PS2;
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* LIBRETRO_GSKIT_PS2_H_ */
|
@ -395,4 +395,3 @@ struct retro_hw_render_interface_vulkan
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -59,4 +59,3 @@ static INLINE int64_t fx32_shiftup(const int32_t a)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -76,4 +76,3 @@ static INLINE size_t fifo_write_avail(fifo_buffer_t *buffer)
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -34,4 +34,3 @@ in a public API, you may need this.
|
||||
#include <compat/msvc.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -37,4 +37,3 @@ size_t read_stdin(char *buf, size_t size);
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -104,4 +104,3 @@ extern const struct trans_stream_backend pipe_backend;
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -44,6 +44,10 @@ typedef struct retro_vfs_dir_handle libretro_vfs_implementation_dir;
|
||||
typedef struct libretro_vfs_implementation_dir libretro_vfs_implementation_dir;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints);
|
||||
|
||||
int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream);
|
||||
@ -84,4 +88,8 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream);
|
||||
|
||||
int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -352,4 +352,3 @@ VkBool32 vulkan_symbol_wrapper_load_device_symbol(VkDevice device, const char *n
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -126,4 +126,3 @@ void co_switch(cothread_t handle)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -104,4 +104,3 @@ void co_switch(cothread_t handle)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -296,4 +296,3 @@ struct string_list *dir_list_new(const char *dir,
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
@ -80,4 +80,3 @@ void fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t size)
|
||||
|
||||
buffer->first = (buffer->first + size) % buffer->size;
|
||||
}
|
||||
|
||||
|
@ -56,4 +56,3 @@ int SDL_CondSignal(SDL_cond *cond)
|
||||
*(volatile bool*)cond = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -29,4 +29,3 @@ clean:
|
||||
rm -f $(TARGET) $(OBJS)
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
|
@ -55,4 +55,3 @@ clean:
|
||||
rm -f $(TARGET) $(OBJS)
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
|
@ -1161,6 +1161,7 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
|
||||
return false;
|
||||
#else
|
||||
struct stat buf;
|
||||
char path[PATH_MAX_LENGTH];
|
||||
#if defined(DT_DIR)
|
||||
const struct dirent *entry = (const struct dirent*)rdir->entry;
|
||||
if (entry->d_type == DT_DIR)
|
||||
@ -1170,7 +1171,6 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
|
||||
return false;
|
||||
#endif
|
||||
/* dirent struct doesn't have d_type, do it the slow way ... */
|
||||
char path[PATH_MAX_LENGTH];
|
||||
path[0] = '\0';
|
||||
fill_pathname_join(path, rdir->orig_path, retro_vfs_dirent_get_name_impl(rdir), sizeof(path));
|
||||
if (stat(path, &buf) < 0)
|
||||
|
758
vfs/vfs_implementation_uwp.cpp
Normal file
758
vfs/vfs_implementation_uwp.cpp
Normal file
@ -0,0 +1,758 @@
|
||||
/* Copyright (C) 2018-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (vfs_implementation_uwp.cpp).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <ppl.h>
|
||||
#include <ppltasks.h>
|
||||
#include <stdio.h>
|
||||
#include <wrl.h>
|
||||
#include <wrl/implements.h>
|
||||
#include <windows.storage.streams.h>
|
||||
#include <robuffer.h>
|
||||
#include <collection.h>
|
||||
#include <functional>
|
||||
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Foundation::Collections;
|
||||
using namespace Windows::Storage;
|
||||
using namespace Windows::Storage::Streams;
|
||||
using namespace Windows::Storage::FileProperties;
|
||||
|
||||
#ifdef RARCH_INTERNAL
|
||||
#ifndef VFS_FRONTEND
|
||||
#define VFS_FRONTEND
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <vfs/vfs_implementation.h>
|
||||
#include <libretro.h>
|
||||
#include <encodings/utf.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <file/file_path.h>
|
||||
#include <retro_assert.h>
|
||||
#include <verbosity.h>
|
||||
#include <string/stdstring.h>
|
||||
#include <retro_environment.h>
|
||||
#include <uwp/uwp_func.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
/* Dear Microsoft
|
||||
* I really appreciate all the effort you took to not provide any
|
||||
* synchronous file APIs and block all attempts to synchronously
|
||||
* wait for the results of async tasks for "smooth user experience",
|
||||
* but I'm not going to run and rewrite all RetroArch cores for
|
||||
* async I/O. I hope you like this hack I made instead.
|
||||
*/
|
||||
template<typename T>
|
||||
T RunAsync(std::function<concurrency::task<T>()> func)
|
||||
{
|
||||
volatile bool finished = false;
|
||||
volatile Platform::Exception^ exception = nullptr;
|
||||
volatile T result;
|
||||
func().then([&finished, &exception, &result](concurrency::task<T> t) {
|
||||
try
|
||||
{
|
||||
result = t.get();
|
||||
}
|
||||
catch (Platform::Exception^ exception_)
|
||||
{
|
||||
exception = exception_;
|
||||
}
|
||||
finished = true;
|
||||
});
|
||||
|
||||
/* Don't stall the UI thread - prevents a deadlock */
|
||||
Windows::UI::Core::CoreWindow^ corewindow = Windows::UI::Core::CoreWindow::GetForCurrentThread();
|
||||
while (!finished)
|
||||
{
|
||||
if (corewindow)
|
||||
corewindow->Dispatcher->ProcessEvents(Windows::UI::Core::CoreProcessEventsOption::ProcessAllIfPresent);
|
||||
}
|
||||
|
||||
if (exception != nullptr)
|
||||
throw exception;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T RunAsyncAndCatchErrors(std::function<concurrency::task<T>()> func, T valueOnError)
|
||||
{
|
||||
try
|
||||
{
|
||||
return RunAsync<T>(func);
|
||||
}
|
||||
catch (Platform::Exception^ e)
|
||||
{
|
||||
return valueOnError;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void windowsize_path(wchar_t* path)
|
||||
{
|
||||
/* UWP deals with paths containing / instead of \ way worse than normal Windows */
|
||||
/* and RetroArch may sometimes mix them (e.g. on archive extraction) */
|
||||
if (!path)
|
||||
return;
|
||||
while (*path)
|
||||
{
|
||||
if (*path == '/')
|
||||
*path = '\\';
|
||||
++path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
/* Damn you, UWP, why no functions for that either */
|
||||
template<typename T>
|
||||
concurrency::task<T^> GetItemFromPathAsync(Platform::String^ path)
|
||||
{
|
||||
static_assert(false, "StorageFile and StorageFolder only");
|
||||
}
|
||||
template<>
|
||||
concurrency::task<StorageFile^> GetItemFromPathAsync(Platform::String^ path)
|
||||
{
|
||||
return concurrency::create_task(StorageFile::GetFileFromPathAsync(path));
|
||||
}
|
||||
template<>
|
||||
concurrency::task<StorageFolder^> GetItemFromPathAsync(Platform::String^ path)
|
||||
{
|
||||
return concurrency::create_task(StorageFolder::GetFolderFromPathAsync(path));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
concurrency::task<T^> GetItemInFolderFromPathAsync(StorageFolder^ folder, Platform::String^ path)
|
||||
{
|
||||
static_assert(false, "StorageFile and StorageFolder only");
|
||||
}
|
||||
template<>
|
||||
concurrency::task<StorageFile^> GetItemInFolderFromPathAsync(StorageFolder^ folder, Platform::String^ path)
|
||||
{
|
||||
if (path->IsEmpty())
|
||||
retro_assert(false); /* Attempt to read a folder as a file - this really should have been caught earlier */
|
||||
return concurrency::create_task(folder->GetFileAsync(path));
|
||||
}
|
||||
template<>
|
||||
concurrency::task<StorageFolder^> GetItemInFolderFromPathAsync(StorageFolder^ folder, Platform::String^ path)
|
||||
{
|
||||
if (path->IsEmpty())
|
||||
return concurrency::create_task(concurrency::create_async([folder]() { return folder; }));
|
||||
return concurrency::create_task(folder->GetFolderAsync(path));
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
/* A list of all StorageFolder objects returned using from the file picker */
|
||||
Platform::Collections::Vector<StorageFolder^> accessible_directories;
|
||||
|
||||
concurrency::task<Platform::String^> TriggerPickerAddDialog()
|
||||
{
|
||||
auto folderPicker = ref new Windows::Storage::Pickers::FolderPicker();
|
||||
folderPicker->SuggestedStartLocation = Windows::Storage::Pickers::PickerLocationId::Desktop;
|
||||
folderPicker->FileTypeFilter->Append("*");
|
||||
|
||||
return concurrency::create_task(folderPicker->PickSingleFolderAsync()).then([](StorageFolder^ folder) {
|
||||
if (folder == nullptr)
|
||||
throw ref new Platform::Exception(E_ABORT, L"Operation cancelled by user");
|
||||
|
||||
/* TODO: check for duplicates */
|
||||
accessible_directories.Append(folder);
|
||||
return folder->Path;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
concurrency::task<T^> LocateStorageItem(Platform::String^ path)
|
||||
{
|
||||
/* Look for a matching directory we can use */
|
||||
for each (StorageFolder^ folder in accessible_directories)
|
||||
{
|
||||
std::wstring folder_path = folder->Path->Data();
|
||||
/* Could be C:\ or C:\Users\somebody - remove the trailing slash to unify them */
|
||||
if (folder_path[folder_path.size() - 1] == '\\')
|
||||
folder_path.erase(folder_path.size() - 1);
|
||||
std::wstring file_path = path->Data();
|
||||
if (file_path.find(folder_path) == 0)
|
||||
{
|
||||
/* Found a match */
|
||||
file_path = file_path.length() > folder_path.length() ? file_path.substr(folder_path.length() + 1) : L"";
|
||||
return concurrency::create_task(GetItemInFolderFromPathAsync<T>(folder, ref new Platform::String(file_path.data())));
|
||||
}
|
||||
}
|
||||
|
||||
/* No matches - try accessing directly, and fallback to user prompt */
|
||||
return concurrency::create_task(GetItemFromPathAsync<T>(path)).then([path](concurrency::task<T^> item) {
|
||||
try
|
||||
{
|
||||
T^ storageItem = item.get();
|
||||
return concurrency::create_task(concurrency::create_async([storageItem]() { return storageItem; }));
|
||||
}
|
||||
catch (Platform::AccessDeniedException^ e)
|
||||
{
|
||||
Windows::UI::Popups::MessageDialog^ dialog =
|
||||
ref new Windows::UI::Popups::MessageDialog("Path \"" + path + "\" is not currently accessible. Please open any containing directory to access it.");
|
||||
dialog->Commands->Append(ref new Windows::UI::Popups::UICommand("Open file picker"));
|
||||
dialog->Commands->Append(ref new Windows::UI::Popups::UICommand("Cancel"));
|
||||
return concurrency::create_task(dialog->ShowAsync()).then([path](Windows::UI::Popups::IUICommand^ cmd) {
|
||||
if (cmd->Label == "Open file picker")
|
||||
{
|
||||
return TriggerPickerAddDialog().then([path](Platform::String^ added_path) {
|
||||
/* Retry */
|
||||
return LocateStorageItem<T>(path);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ref new Platform::Exception(E_ABORT, L"Operation cancelled by user");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
IStorageItem^ LocateStorageFileOrFolder(Platform::String^ path)
|
||||
{
|
||||
if (!path || path->IsEmpty())
|
||||
return nullptr;
|
||||
|
||||
if (*(path->End() - 1) == '\\')
|
||||
{
|
||||
/* Ends with a slash, so it's definitely a directory */
|
||||
return RunAsyncAndCatchErrors<StorageFolder^>([=]() {
|
||||
return concurrency::create_task(LocateStorageItem<StorageFolder>(path));
|
||||
}, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No final slash - probably a file (since RetroArch usually slash-terminates dirs), but there is still a chance it's a directory */
|
||||
IStorageItem^ item;
|
||||
item = RunAsyncAndCatchErrors<StorageFile^>([=]() {
|
||||
return concurrency::create_task(LocateStorageItem<StorageFile>(path));
|
||||
}, nullptr);
|
||||
if (!item)
|
||||
{
|
||||
item = RunAsyncAndCatchErrors<StorageFolder^>([=]() {
|
||||
return concurrency::create_task(LocateStorageItem<StorageFolder>(path));
|
||||
}, nullptr);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VFS_FRONTEND
|
||||
struct retro_vfs_file_handle
|
||||
#else
|
||||
struct libretro_vfs_implementation_file
|
||||
#endif
|
||||
{
|
||||
IRandomAccessStream^ fp;
|
||||
char* orig_path;
|
||||
};
|
||||
|
||||
libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints)
|
||||
{
|
||||
if (!path || !*path)
|
||||
return NULL;
|
||||
|
||||
if (!path_is_absolute(path))
|
||||
{
|
||||
RARCH_WARN("Something tried to access files from current directory ('%s'). This is not allowed on UWP.\n", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (path_char_is_slash(path[strlen(path) - 1]))
|
||||
{
|
||||
RARCH_WARN("Trying to open a directory as file?! ('%s')\n", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* dirpath = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_basedir(dirpath, path, PATH_MAX_LENGTH);
|
||||
wchar_t *dirpath_wide = utf8_to_utf16_string_alloc(dirpath);
|
||||
windowsize_path(dirpath_wide);
|
||||
Platform::String^ dirpath_str = ref new Platform::String(dirpath_wide);
|
||||
free(dirpath_wide);
|
||||
free(dirpath);
|
||||
|
||||
char* filename = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_base(filename, path, PATH_MAX_LENGTH);
|
||||
wchar_t *filename_wide = utf8_to_utf16_string_alloc(filename);
|
||||
Platform::String^ filename_str = ref new Platform::String(filename_wide);
|
||||
free(filename_wide);
|
||||
free(filename);
|
||||
|
||||
retro_assert(!dirpath_str->IsEmpty() && !filename_str->IsEmpty());
|
||||
|
||||
return RunAsyncAndCatchErrors<libretro_vfs_implementation_file*>([=]() {
|
||||
return concurrency::create_task(LocateStorageItem<StorageFolder>(dirpath_str)).then([=](StorageFolder^ dir) {
|
||||
if (mode == RETRO_VFS_FILE_ACCESS_READ)
|
||||
return dir->GetFileAsync(filename_str);
|
||||
else
|
||||
return dir->CreateFileAsync(filename_str, (mode & RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING) != 0 ?
|
||||
CreationCollisionOption::OpenIfExists : CreationCollisionOption::ReplaceExisting);
|
||||
}).then([=](StorageFile^ file) {
|
||||
FileAccessMode accessMode = mode == RETRO_VFS_FILE_ACCESS_READ ?
|
||||
FileAccessMode::Read : FileAccessMode::ReadWrite;
|
||||
return file->OpenAsync(accessMode);
|
||||
}).then([=](IRandomAccessStream^ fpstream) {
|
||||
libretro_vfs_implementation_file *stream = (libretro_vfs_implementation_file*)calloc(1, sizeof(*stream));
|
||||
if (!stream)
|
||||
return (libretro_vfs_implementation_file*)NULL;
|
||||
|
||||
stream->orig_path = strdup(path);
|
||||
stream->fp = fpstream;
|
||||
stream->fp->Seek(0);
|
||||
return stream;
|
||||
});
|
||||
}, NULL);
|
||||
}
|
||||
|
||||
int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
|
||||
{
|
||||
if (!stream || !stream->fp)
|
||||
return -1;
|
||||
|
||||
/* Apparently, this is how you close a file in WinRT */
|
||||
/* Yes, really */
|
||||
stream->fp = nullptr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream)
|
||||
{
|
||||
return false; /* TODO */
|
||||
}
|
||||
|
||||
int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream)
|
||||
{
|
||||
if (!stream || !stream->fp)
|
||||
return 0;
|
||||
return stream->fp->Size;
|
||||
}
|
||||
|
||||
int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length)
|
||||
{
|
||||
if (!stream || !stream->fp)
|
||||
return -1;
|
||||
stream->fp->Size = length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
|
||||
{
|
||||
if (!stream || !stream->fp)
|
||||
return -1;
|
||||
return stream->fp->Position;
|
||||
}
|
||||
|
||||
int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position)
|
||||
{
|
||||
if (!stream || !stream->fp)
|
||||
return -1;
|
||||
|
||||
switch (seek_position)
|
||||
{
|
||||
case RETRO_VFS_SEEK_POSITION_START:
|
||||
stream->fp->Seek(offset);
|
||||
break;
|
||||
|
||||
case RETRO_VFS_SEEK_POSITION_CURRENT:
|
||||
stream->fp->Seek(stream->fp->Position + offset);
|
||||
break;
|
||||
|
||||
case RETRO_VFS_SEEK_POSITION_END:
|
||||
stream->fp->Seek(stream->fp->Size - offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is some pure magic and I have absolutely no idea how it works */
|
||||
/* Wraps a raw buffer into a WinRT object */
|
||||
/* https://stackoverflow.com/questions/10520335/how-to-wrap-a-char-buffer-in-a-winrt-ibuffer-in-c */
|
||||
class NativeBuffer :
|
||||
public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::RuntimeClassType::WinRtClassicComMix>,
|
||||
ABI::Windows::Storage::Streams::IBuffer,
|
||||
Windows::Storage::Streams::IBufferByteAccess>
|
||||
{
|
||||
public:
|
||||
virtual ~NativeBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT __stdcall RuntimeClassInitialize(byte *buffer, uint32_t capacity, uint32_t length)
|
||||
{
|
||||
m_buffer = buffer;
|
||||
m_capacity = capacity;
|
||||
m_length = length;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall Buffer(byte **value)
|
||||
{
|
||||
if (m_buffer == nullptr)
|
||||
return E_INVALIDARG;
|
||||
*value = m_buffer;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall get_Capacity(uint32_t *value)
|
||||
{
|
||||
*value = m_capacity;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall get_Length(uint32_t *value)
|
||||
{
|
||||
*value = m_length;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall put_Length(uint32_t value)
|
||||
{
|
||||
if (value > m_capacity)
|
||||
return E_INVALIDARG;
|
||||
m_length = value;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
byte *m_buffer;
|
||||
uint32_t m_capacity;
|
||||
uint32_t m_length;
|
||||
};
|
||||
|
||||
IBuffer^ CreateNativeBuffer(void* buf, uint32_t capacity, uint32_t length)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<NativeBuffer> nativeBuffer;
|
||||
Microsoft::WRL::Details::MakeAndInitialize<NativeBuffer>(&nativeBuffer, (byte *)buf, capacity, length);
|
||||
auto iinspectable = (IInspectable *)reinterpret_cast<IInspectable *>(nativeBuffer.Get());
|
||||
IBuffer ^buffer = reinterpret_cast<IBuffer ^>(iinspectable);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, void *s, uint64_t len)
|
||||
{
|
||||
if (!stream || !stream->fp || !s)
|
||||
return -1;
|
||||
|
||||
IBuffer^ buffer = CreateNativeBuffer(s, len, 0);
|
||||
return RunAsyncAndCatchErrors<int64_t>([=]() {
|
||||
return concurrency::create_task(stream->fp->ReadAsync(buffer, buffer->Capacity, InputStreamOptions::None)).then([=](IBuffer^ buf) {
|
||||
retro_assert(buf == buffer);
|
||||
return (int64_t)buffer->Length;
|
||||
});
|
||||
}, -1);
|
||||
}
|
||||
|
||||
int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len)
|
||||
{
|
||||
if (!stream || !stream->fp || !s)
|
||||
return -1;
|
||||
|
||||
IBuffer^ buffer = CreateNativeBuffer(const_cast<void*>(s), len, len);
|
||||
return RunAsyncAndCatchErrors<int64_t>([=]() {
|
||||
return concurrency::create_task(stream->fp->WriteAsync(buffer)).then([=](unsigned int written) {
|
||||
return (int64_t)written;
|
||||
});
|
||||
}, -1);
|
||||
}
|
||||
|
||||
int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream)
|
||||
{
|
||||
if (!stream || !stream->fp)
|
||||
return -1;
|
||||
|
||||
return RunAsyncAndCatchErrors<int>([=]() {
|
||||
return concurrency::create_task(stream->fp->FlushAsync()).then([=](bool this_value_is_not_even_documented_wtf) {
|
||||
/* The bool value may be reporting an error or something, but just leave it alone for now */
|
||||
/* https://github.com/MicrosoftDocs/winrt-api/issues/841 */
|
||||
return 0;
|
||||
});
|
||||
}, -1);
|
||||
}
|
||||
|
||||
int retro_vfs_file_remove_impl(const char *path)
|
||||
{
|
||||
if (!path || !*path)
|
||||
return -1;
|
||||
|
||||
wchar_t *path_wide = utf8_to_utf16_string_alloc(path);
|
||||
windowsize_path(path_wide);
|
||||
Platform::String^ path_str = ref new Platform::String(path_wide);
|
||||
free(path_wide);
|
||||
|
||||
return RunAsyncAndCatchErrors<int>([=]() {
|
||||
return concurrency::create_task(LocateStorageItem<StorageFile>(path_str)).then([=](StorageFile^ file) {
|
||||
return file->DeleteAsync(StorageDeleteOption::PermanentDelete);
|
||||
}).then([=]() {
|
||||
return 0;
|
||||
});
|
||||
}, -1);
|
||||
}
|
||||
|
||||
/* TODO: this may not work if trying to move a directory */
|
||||
int retro_vfs_file_rename_impl(const char *old_path, const char *new_path)
|
||||
{
|
||||
if (!old_path || !*old_path || !new_path || !*new_path)
|
||||
return -1;
|
||||
|
||||
wchar_t* old_path_wide = utf8_to_utf16_string_alloc(old_path);
|
||||
Platform::String^ old_path_str = ref new Platform::String(old_path_wide);
|
||||
free(old_path_wide);
|
||||
|
||||
char* new_dir_path = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_basedir(new_dir_path, new_path, PATH_MAX_LENGTH);
|
||||
wchar_t *new_dir_path_wide = utf8_to_utf16_string_alloc(new_dir_path);
|
||||
windowsize_path(new_dir_path_wide);
|
||||
Platform::String^ new_dir_path_str = ref new Platform::String(new_dir_path_wide);
|
||||
free(new_dir_path_wide);
|
||||
free(new_dir_path);
|
||||
|
||||
char* new_file_name = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_base(new_file_name, new_path, PATH_MAX_LENGTH);
|
||||
wchar_t *new_file_name_wide = utf8_to_utf16_string_alloc(new_file_name);
|
||||
Platform::String^ new_file_name_str = ref new Platform::String(new_file_name_wide);
|
||||
free(new_file_name_wide);
|
||||
free(new_file_name);
|
||||
|
||||
retro_assert(!old_path_str->IsEmpty() && !new_dir_path_str->IsEmpty() && !new_file_name_str->IsEmpty());
|
||||
|
||||
return RunAsyncAndCatchErrors<int>([=]() {
|
||||
concurrency::task<StorageFile^> old_file_task = concurrency::create_task(LocateStorageItem<StorageFile>(old_path_str));
|
||||
concurrency::task<StorageFolder^> new_dir_task = concurrency::create_task(LocateStorageItem<StorageFolder>(new_dir_path_str));
|
||||
return concurrency::create_task([=] {
|
||||
/* Run these two tasks in parallel */
|
||||
/* TODO: There may be some cleaner way to express this */
|
||||
concurrency::task_group group;
|
||||
group.run([=] { return old_file_task; });
|
||||
group.run([=] { return new_dir_task; });
|
||||
group.wait();
|
||||
}).then([=]() {
|
||||
return old_file_task.get()->MoveAsync(new_dir_task.get(), new_file_name_str, NameCollisionOption::ReplaceExisting);
|
||||
}).then([=]() {
|
||||
return 0;
|
||||
});
|
||||
}, -1);
|
||||
}
|
||||
|
||||
const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream)
|
||||
{
|
||||
/* should never happen, do something noisy so caller can be fixed */
|
||||
if (!stream)
|
||||
abort();
|
||||
return stream->orig_path;
|
||||
}
|
||||
|
||||
int retro_vfs_stat_impl(const char *path, int32_t *size)
|
||||
{
|
||||
if (!path || !*path)
|
||||
return 0;
|
||||
|
||||
wchar_t *path_wide = utf8_to_utf16_string_alloc(path);
|
||||
windowsize_path(path_wide);
|
||||
Platform::String^ path_str = ref new Platform::String(path_wide);
|
||||
free(path_wide);
|
||||
|
||||
IStorageItem^ item = LocateStorageFileOrFolder(path_str);
|
||||
if (!item)
|
||||
return 0;
|
||||
|
||||
return RunAsyncAndCatchErrors<int>([=]() {
|
||||
return concurrency::create_task(item->GetBasicPropertiesAsync()).then([=](BasicProperties^ properties) {
|
||||
if (size)
|
||||
*size = properties->Size;
|
||||
return item->IsOfType(StorageItemTypes::Folder) ? RETRO_VFS_STAT_IS_VALID | RETRO_VFS_STAT_IS_DIRECTORY : RETRO_VFS_STAT_IS_VALID;
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
int retro_vfs_mkdir_impl(const char *dir)
|
||||
{
|
||||
if (!dir || !*dir)
|
||||
return -1;
|
||||
|
||||
char* dir_local = strdup(dir);
|
||||
/* If the path ends with a slash, we have to remove it for basename to work */
|
||||
char* tmp = dir_local + strlen(dir_local) - 1;
|
||||
if (path_char_is_slash(*tmp))
|
||||
*tmp = 0;
|
||||
|
||||
char* dir_name = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_base(dir_name, dir_local, PATH_MAX_LENGTH);
|
||||
wchar_t *dir_name_wide = utf8_to_utf16_string_alloc(dir_name);
|
||||
Platform::String^ dir_name_str = ref new Platform::String(dir_name_wide);
|
||||
free(dir_name_wide);
|
||||
free(dir_name);
|
||||
|
||||
char* parent_path = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_parent_dir(parent_path, dir_local, PATH_MAX_LENGTH);
|
||||
wchar_t *parent_path_wide = utf8_to_utf16_string_alloc(parent_path);
|
||||
windowsize_path(parent_path_wide);
|
||||
Platform::String^ parent_path_str = ref new Platform::String(parent_path_wide);
|
||||
free(parent_path_wide);
|
||||
free(parent_path);
|
||||
|
||||
retro_assert(!dir_name_str->IsEmpty() && !parent_path_str->IsEmpty());
|
||||
|
||||
free(dir_local);
|
||||
|
||||
return RunAsyncAndCatchErrors<int>([=]() {
|
||||
return concurrency::create_task(LocateStorageItem<StorageFolder>(parent_path_str)).then([=](StorageFolder^ parent) {
|
||||
return parent->CreateFolderAsync(dir_name_str);
|
||||
}).then([=](concurrency::task<StorageFolder^> new_dir) {
|
||||
try
|
||||
{
|
||||
new_dir.get();
|
||||
}
|
||||
catch (Platform::COMException^ e)
|
||||
{
|
||||
if (e->HResult == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
|
||||
return -2;
|
||||
throw;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}, -1);
|
||||
}
|
||||
|
||||
#ifdef VFS_FRONTEND
|
||||
struct retro_vfs_dir_handle
|
||||
#else
|
||||
struct libretro_vfs_implementation_dir
|
||||
#endif
|
||||
{
|
||||
IVectorView<IStorageItem^>^ directory;
|
||||
IIterator<IStorageItem^>^ entry;
|
||||
char *entry_name;
|
||||
};
|
||||
|
||||
libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *name, bool include_hidden)
|
||||
{
|
||||
libretro_vfs_implementation_dir *rdir;
|
||||
|
||||
if (!name || !*name)
|
||||
return NULL;
|
||||
|
||||
rdir = (libretro_vfs_implementation_dir*)calloc(1, sizeof(*rdir));
|
||||
if (!rdir)
|
||||
return NULL;
|
||||
|
||||
wchar_t *name_wide = utf8_to_utf16_string_alloc(name);
|
||||
windowsize_path(name_wide);
|
||||
Platform::String^ name_str = ref new Platform::String(name_wide);
|
||||
free(name_wide);
|
||||
|
||||
rdir->directory = RunAsyncAndCatchErrors<IVectorView<IStorageItem^>^>([=]() {
|
||||
return concurrency::create_task(LocateStorageItem<StorageFolder>(name_str)).then([=](StorageFolder^ folder) {
|
||||
return folder->GetItemsAsync();
|
||||
});
|
||||
}, nullptr);
|
||||
|
||||
if (rdir->directory)
|
||||
return rdir;
|
||||
|
||||
free(rdir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
|
||||
{
|
||||
if (!rdir->entry)
|
||||
{
|
||||
rdir->entry = rdir->directory->First();
|
||||
return rdir->entry->HasCurrent;
|
||||
}
|
||||
else
|
||||
{
|
||||
return rdir->entry->MoveNext();
|
||||
}
|
||||
}
|
||||
|
||||
const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir)
|
||||
{
|
||||
if (rdir->entry_name)
|
||||
free(rdir->entry_name);
|
||||
rdir->entry_name = utf16_to_utf8_string_alloc(rdir->entry->Current->Name->Data());
|
||||
return rdir->entry_name;
|
||||
}
|
||||
|
||||
bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
|
||||
{
|
||||
return rdir->entry->Current->IsOfType(StorageItemTypes::Folder);
|
||||
}
|
||||
|
||||
int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
|
||||
{
|
||||
if (!rdir)
|
||||
return -1;
|
||||
|
||||
if (rdir->entry_name)
|
||||
free(rdir->entry_name);
|
||||
rdir->entry = nullptr;
|
||||
rdir->directory = nullptr;
|
||||
|
||||
free(rdir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool uwp_is_path_accessible_using_standard_io(char *path)
|
||||
{
|
||||
char *relative_path_abbrev = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
fill_pathname_abbreviate_special(relative_path_abbrev, path, PATH_MAX_LENGTH * sizeof(char));
|
||||
|
||||
bool result = strlen(relative_path_abbrev) >= 2 && (relative_path_abbrev[0] == ':' || relative_path_abbrev[0] == '~') && path_char_is_slash(relative_path_abbrev[1]);
|
||||
|
||||
free(relative_path_abbrev);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool uwp_drive_exists(const char *path)
|
||||
{
|
||||
if (!path || !*path)
|
||||
return 0;
|
||||
|
||||
wchar_t *path_wide = utf8_to_utf16_string_alloc(path);
|
||||
Platform::String^ path_str = ref new Platform::String(path_wide);
|
||||
free(path_wide);
|
||||
|
||||
return RunAsyncAndCatchErrors<bool>([=]() {
|
||||
return concurrency::create_task(StorageFolder::GetFolderFromPathAsync(path_str)).then([](StorageFolder^ properties) {
|
||||
return true;
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
char* uwp_trigger_picker(void)
|
||||
{
|
||||
return RunAsyncAndCatchErrors<char*>([=]() {
|
||||
return TriggerPickerAddDialog().then([](Platform::String^ path) {
|
||||
return utf16_to_utf8_string_alloc(path->Data());
|
||||
});
|
||||
}, NULL);
|
||||
}
|
Loading…
Reference in New Issue
Block a user