Merge branch 'master' into Shader_Save_Load

This commit is contained in:
HyperspaceMadness 2020-11-10 17:05:23 -05:00 committed by GitHub
commit 5008ac6eb0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 882 additions and 362 deletions

View File

@ -99,8 +99,8 @@ matrix:
android: android:
components: components:
- tools - tools
- build-tools-28.0.3 - build-tools-29.0.3
- android-28 - android-29
install: install:
- echo y | sdkmanager "ndk-bundle" - echo y | sdkmanager "ndk-bundle"
before_script: before_script:

View File

@ -156,8 +156,8 @@ endif
ifeq ($(TARGET), retroarch_3ds) ifeq ($(TARGET), retroarch_3ds)
OBJ += frontend/drivers/platform_ctr.o OBJ += frontend/drivers/platform_ctr.o
endif endif
# Git Version # Git Version
ifeq ($(HAVE_GIT_VERSION), 1)
GIT_VERSION_CACHEDIR = $(if $(OBJDIR),$(OBJDIR),$(CURDIR)) GIT_VERSION_CACHEDIR = $(if $(OBJDIR),$(OBJDIR),$(CURDIR))
GIT_VERSION_CACHEFILE = $(GIT_VERSION_CACHEDIR)/git-version.cache GIT_VERSION_CACHEFILE = $(GIT_VERSION_CACHEDIR)/git-version.cache
@ -185,6 +185,7 @@ ifneq ($(GIT_VERSION),) # Enable version_git.o?
DEFINES += -DHAVE_GIT_VERSION -DGIT_VERSION=$(GIT_VERSION) DEFINES += -DHAVE_GIT_VERSION -DGIT_VERSION=$(GIT_VERSION)
OBJ += version_git.o OBJ += version_git.o
endif endif
endif
# General object files # General object files
ifeq ($(HAVE_DR_MP3), 1) ifeq ($(HAVE_DR_MP3), 1)
@ -2260,6 +2261,7 @@ ifeq ($(HAVE_STATIC_VIDEO_FILTERS), 1)
gfx/video_filters/normal2x.o \ gfx/video_filters/normal2x.o \
gfx/video_filters/normal2x_width.o \ gfx/video_filters/normal2x_width.o \
gfx/video_filters/normal2x_height.o \ gfx/video_filters/normal2x_height.o \
gfx/video_filters/normal4x.o \
gfx/video_filters/scanline2x.o \ gfx/video_filters/scanline2x.o \
gfx/video_filters/grid2x.o \ gfx/video_filters/grid2x.o \
gfx/video_filters/grid3x.o \ gfx/video_filters/grid3x.o \

View File

@ -83,12 +83,12 @@ static void *alsa_init(const char *device, unsigned rate, unsigned latency,
if (snd_pcm_hw_params_malloc(&params) < 0) if (snd_pcm_hw_params_malloc(&params) < 0)
goto error; goto error;
alsa->has_float = find_float_format(alsa->pcm, params);
format = alsa->has_float ? SND_PCM_FORMAT_FLOAT : SND_PCM_FORMAT_S16;
if (snd_pcm_hw_params_any(alsa->pcm, params) < 0) if (snd_pcm_hw_params_any(alsa->pcm, params) < 0)
goto error; goto error;
alsa->has_float = find_float_format(alsa->pcm, params);
format = alsa->has_float ? SND_PCM_FORMAT_FLOAT : SND_PCM_FORMAT_S16;
if (snd_pcm_hw_params_set_access( if (snd_pcm_hw_params_set_access(
alsa->pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) alsa->pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
goto error; goto error;

View File

@ -173,10 +173,11 @@ static void *alsa_thread_init(const char *device,
TRY_ALSA(snd_pcm_open(&alsa->pcm, alsa_dev, SND_PCM_STREAM_PLAYBACK, 0)); TRY_ALSA(snd_pcm_open(&alsa->pcm, alsa_dev, SND_PCM_STREAM_PLAYBACK, 0));
TRY_ALSA(snd_pcm_hw_params_malloc(&params)); TRY_ALSA(snd_pcm_hw_params_malloc(&params));
TRY_ALSA(snd_pcm_hw_params_any(alsa->pcm, params));
alsa->has_float = alsathread_find_float_format(alsa->pcm, params); alsa->has_float = alsathread_find_float_format(alsa->pcm, params);
format = alsa->has_float ? SND_PCM_FORMAT_FLOAT : SND_PCM_FORMAT_S16; format = alsa->has_float ? SND_PCM_FORMAT_FLOAT : SND_PCM_FORMAT_S16;
TRY_ALSA(snd_pcm_hw_params_any(alsa->pcm, params));
TRY_ALSA(snd_pcm_hw_params_set_access( TRY_ALSA(snd_pcm_hw_params_set_access(
alsa->pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED)); alsa->pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED));
TRY_ALSA(snd_pcm_hw_params_set_format(alsa->pcm, params, format)); TRY_ALSA(snd_pcm_hw_params_set_format(alsa->pcm, params, format));

View File

@ -1597,7 +1597,8 @@ static int rcheevos_match_value(const char* val, const char* match)
void rcheevos_validate_config_settings(void) void rcheevos_validate_config_settings(void)
{ {
const rc_disallowed_core_settings_t* core_filter = rc_disallowed_core_settings; const rc_disallowed_core_settings_t
*core_filter = rc_disallowed_core_settings;
struct retro_system_info* system = runloop_get_libretro_system_info(); struct retro_system_info* system = runloop_get_libretro_system_info();
if (!system->library_name || !rcheevos_hardcore_active()) if (!system->library_name || !rcheevos_hardcore_active())
return; return;
@ -1610,25 +1611,31 @@ void rcheevos_validate_config_settings(void)
if (rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts)) if (rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts))
{ {
const rc_disallowed_setting_t* disallowed_setting = core_filter->disallowed_settings;
const char* key;
const char* val;
int i; int i;
const char *key = NULL;
const char *val = NULL;
const rc_disallowed_setting_t
*disallowed_setting = core_filter->disallowed_settings;
int allowed = 1; int allowed = 1;
size_t key_len;
for (; disallowed_setting->setting; ++disallowed_setting) for (; disallowed_setting->setting; ++disallowed_setting)
{ {
size_t key_len;
key = disallowed_setting->setting; key = disallowed_setting->setting;
key_len = strlen(key); key_len = strlen(key);
if (key[key_len - 1] == '*') if (key[key_len - 1] == '*')
{ {
for (i = 0; i < coreopts->size; i++) for (i = 0; i < coreopts->size; i++)
{ {
if (string_starts_with_size(coreopts->opts[i].key, key, key_len - 1)) if (string_starts_with_size(
coreopts->opts[i].key, key, key_len - 1))
{ {
val = core_option_manager_get_val(coreopts, i); const char* val =core_option_manager_get_val(coreopts, i);
if (rcheevos_match_value(val, disallowed_setting->value)) if (val)
{
if (rcheevos_match_value(
val, disallowed_setting->value))
{ {
key = coreopts->opts[i].key; key = coreopts->opts[i].key;
allowed = 0; allowed = 0;
@ -1637,6 +1644,7 @@ void rcheevos_validate_config_settings(void)
} }
} }
} }
}
else else
{ {
for (i = 0; i < coreopts->size; i++) for (i = 0; i < coreopts->size; i++)

View File

@ -196,6 +196,7 @@ enum event_command
CMD_EVENT_OSK_TOGGLE, CMD_EVENT_OSK_TOGGLE,
CMD_EVENT_RECORDING_TOGGLE, CMD_EVENT_RECORDING_TOGGLE,
CMD_EVENT_STREAMING_TOGGLE, CMD_EVENT_STREAMING_TOGGLE,
CMD_EVENT_RUNAHEAD_TOGGLE,
CMD_EVENT_AI_SERVICE_TOGGLE, CMD_EVENT_AI_SERVICE_TOGGLE,
CMD_EVENT_BSV_RECORDING_TOGGLE, CMD_EVENT_BSV_RECORDING_TOGGLE,
CMD_EVENT_SHADER_NEXT, CMD_EVENT_SHADER_NEXT,

View File

@ -1146,7 +1146,11 @@ static const int default_content_favorites_size = 200;
/* Default scale factor for non-frambuffer-based display /* Default scale factor for non-frambuffer-based display
* drivers and display widgets */ * drivers and display widgets */
#if defined(VITA)
#define DEFAULT_MENU_SCALE_FACTOR 1.5f
#else
#define DEFAULT_MENU_SCALE_FACTOR 1.0f #define DEFAULT_MENU_SCALE_FACTOR 1.0f
#endif
/* Specifies whether display widgets should be scaled /* Specifies whether display widgets should be scaled
* automatically using the default menu scale factor */ * automatically using the default menu scale factor */
#define DEFAULT_MENU_WIDGET_SCALE_AUTO true #define DEFAULT_MENU_WIDGET_SCALE_AUTO true

View File

@ -563,6 +563,13 @@ static const struct retro_keybind retro_keybinds_1[] = {
RARCH_STREAMING_TOGGLE, NO_BTN, NO_BTN, 0, RARCH_STREAMING_TOGGLE, NO_BTN, NO_BTN, 0,
true true
}, },
{
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
MENU_ENUM_LABEL_VALUE_INPUT_META_RUNAHEAD_TOGGLE, RETROK_UNKNOWN,
RARCH_RUNAHEAD_TOGGLE, NO_BTN, NO_BTN, 0,
true
},
{ {
NULL, NULL, NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE, AXIS_NONE, AXIS_NONE, AXIS_NONE,
@ -1110,6 +1117,13 @@ static const struct retro_keybind retro_keybinds_1[] = {
RARCH_STREAMING_TOGGLE, NO_BTN, NO_BTN, 0, RARCH_STREAMING_TOGGLE, NO_BTN, NO_BTN, 0,
true true
}, },
{
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
MENU_ENUM_LABEL_VALUE_INPUT_META_RUNAHEAD_TOGGLE, RETROK_UNKNOWN,
RARCH_RUNAHEAD_TOGGLE, NO_BTN, NO_BTN, 0,
true
},
{ {
NULL, NULL, NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE, AXIS_NONE, AXIS_NONE, AXIS_NONE,
@ -1667,6 +1681,13 @@ static const struct retro_keybind retro_keybinds_1[] = {
RARCH_STREAMING_TOGGLE, NO_BTN, NO_BTN, 0, RARCH_STREAMING_TOGGLE, NO_BTN, NO_BTN, 0,
true true
}, },
{
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
MENU_ENUM_LABEL_VALUE_INPUT_META_RUNAHEAD_TOGGLE, RETROK_UNKNOWN,
RARCH_RUNAHEAD_TOGGLE, NO_BTN, NO_BTN, 0,
true
},
{ {
NULL, NULL, NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE, AXIS_NONE, AXIS_NONE, AXIS_NONE,

View File

@ -10,31 +10,26 @@ struct Backoff
int64_t minAmount; int64_t minAmount;
int64_t maxAmount; int64_t maxAmount;
int64_t current; int64_t current;
int fails;
std::mt19937_64 randGenerator; std::mt19937_64 randGenerator;
std::uniform_real_distribution<> randDistribution; std::uniform_real_distribution<> randDistribution;
double rand01() { return randDistribution(randGenerator); }
Backoff(int64_t min, int64_t max) Backoff(int64_t min, int64_t max)
: minAmount(min) : minAmount(min)
, maxAmount(max) , maxAmount(max)
, current(min) , current(min)
, fails(0)
, randGenerator((uint64_t)time(0)) , randGenerator((uint64_t)time(0))
{ {
} }
void reset() void reset()
{ {
fails = 0;
current = minAmount; current = minAmount;
} }
int64_t nextDelay() int64_t nextDelay()
{ {
++fails; int64_t delay = (int64_t)((double)current * 2.0 *
int64_t delay = (int64_t)((double)current * 2.0 * rand01()); randDistribution(randGenerator));
current = std::min(current + delay, maxAmount); current = std::min(current + delay, maxAmount);
return current; return current;
} }

View File

@ -10,22 +10,10 @@
#include <chrono> #include <chrono>
#include <mutex> #include <mutex>
#ifndef DISCORD_DISABLE_IO_THREAD
#include <condition_variable>
#include <thread>
#endif
struct QueuedMessage struct QueuedMessage
{ {
size_t length; size_t length;
char buffer[16384]; char buffer[16384];
void Copy(const QueuedMessage& other)
{
length = other.length;
if (length)
memcpy(buffer, other.buffer, length);
}
}; };
struct User struct User
@ -80,66 +68,13 @@ static User connectedUser;
static Backoff ReconnectTimeMs(500, 60 * 1000); static Backoff ReconnectTimeMs(500, 60 * 1000);
static auto NextConnect = std::chrono::system_clock::now(); static auto NextConnect = std::chrono::system_clock::now();
#ifndef DISCORD_DISABLE_IO_THREAD static void update_reconnect_time(void)
static void Discord_UpdateConnection(void);
class IoThreadHolder
{
private:
std::atomic_bool keepRunning{true};
std::mutex waitForIOMutex;
std::condition_variable waitForIOActivity;
std::thread ioThread;
public:
void Start()
{
keepRunning.store(true);
ioThread = std::thread([&]() {
const std::chrono::duration<int64_t, std::milli> maxWait{500LL};
Discord_UpdateConnection();
while (keepRunning.load()) {
std::unique_lock<std::mutex> lock(waitForIOMutex);
waitForIOActivity.wait_for(lock, maxWait);
Discord_UpdateConnection();
}
});
}
void Notify() { waitForIOActivity.notify_all(); }
void Stop()
{
keepRunning.exchange(false);
Notify();
if (ioThread.joinable())
ioThread.join();
}
~IoThreadHolder() { Stop(); }
};
#else
class IoThreadHolder
{
public:
void Start() {}
void Stop() {}
void Notify() {}
};
#endif /* DISCORD_DISABLE_IO_THREAD */
static IoThreadHolder* IoThread{nullptr};
static void UpdateReconnectTime(void)
{ {
NextConnect = std::chrono::system_clock::now() + NextConnect = std::chrono::system_clock::now() +
std::chrono::duration<int64_t, std::milli>{ReconnectTimeMs.nextDelay()}; std::chrono::duration<int64_t, std::milli>{ReconnectTimeMs.nextDelay()};
} }
#ifdef DISCORD_DISABLE_IO_THREAD
extern "C" void Discord_UpdateConnection(void) extern "C" void Discord_UpdateConnection(void)
#else
static void Discord_UpdateConnection(void)
#endif
{ {
if (!Connection) if (!Connection)
return; return;
@ -148,7 +83,7 @@ static void Discord_UpdateConnection(void)
{ {
if (std::chrono::system_clock::now() >= NextConnect) if (std::chrono::system_clock::now() >= NextConnect)
{ {
UpdateReconnectTime(); update_reconnect_time();
Connection->Open(); Connection->Open();
} }
} }
@ -268,16 +203,19 @@ static void Discord_UpdateConnection(void)
if (QueuedPresence.length) if (QueuedPresence.length)
{ {
QueuedMessage local; QueuedMessage local;
{
std::lock_guard<std::mutex> guard(PresenceMutex); std::lock_guard<std::mutex> guard(PresenceMutex);
local.Copy(QueuedPresence); local.length = QueuedPresence.length;
if (local.length)
memcpy(local.buffer, QueuedPresence.buffer, local.length);
QueuedPresence.length = 0; QueuedPresence.length = 0;
}
if (!Connection->Write(local.buffer, local.length)) if (!Connection->Write(local.buffer, local.length))
{ {
/* if we fail to send, requeue */ /* if we fail to send, requeue */
std::lock_guard<std::mutex> guard(PresenceMutex); std::lock_guard<std::mutex> guard(PresenceMutex);
QueuedPresence.Copy(local); QueuedPresence.length = local.length;
if (QueuedPresence.length)
memcpy(QueuedPresence.buffer, local.buffer, QueuedPresence.length);
} }
} }
@ -298,8 +236,6 @@ static bool RegisterForEvent(const char* evtName)
qmessage->length = qmessage->length =
JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName); JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
SendQueue.CommitAdd(); SendQueue.CommitAdd();
if (IoThread)
IoThread->Notify();
return true; return true;
} }
return false; return false;
@ -313,8 +249,6 @@ static bool DeregisterForEvent(const char* evtName)
qmessage->length = qmessage->length =
JsonWriteUnsubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName); JsonWriteUnsubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
SendQueue.CommitAdd(); SendQueue.CommitAdd();
if (IoThread)
IoThread->Notify();
return true; return true;
} }
return false; return false;
@ -326,10 +260,6 @@ extern "C" void Discord_Initialize(
int autoRegister, int autoRegister,
const char* optionalSteamId) const char* optionalSteamId)
{ {
IoThread = new (std::nothrow) IoThreadHolder();
if (!IoThread)
return;
if (autoRegister) if (autoRegister)
{ {
if (optionalSteamId && optionalSteamId[0]) if (optionalSteamId && optionalSteamId[0])
@ -357,13 +287,15 @@ extern "C" void Discord_Initialize(
Connection = RpcConnection::Create(applicationId); Connection = RpcConnection::Create(applicationId);
Connection->onConnect = [](JsonDocument& readyMessage) Connection->onConnect = [](JsonDocument& readyMessage)
{ {
Discord_UpdateHandlers(&QueuedHandlers);
char *userId = NULL; char *userId = NULL;
char *username = NULL; char *username = NULL;
char *avatar = NULL; char *avatar = NULL;
char *discriminator = NULL; char *discriminator = NULL;
bool in_data = false;
bool in_user = false;
Discord_UpdateHandlers(&QueuedHandlers);
bool in_data = false, in_user = false;
for (JsonReader r(readyMessage); r.NextKey();) for (JsonReader r(readyMessage); r.NextKey();)
{ {
if (r.depth == 1) if (r.depth == 1)
@ -372,15 +304,17 @@ extern "C" void Discord_Initialize(
in_user = false; in_user = false;
} }
else if (r.depth == 2 && in_data) else if (r.depth == 2 && in_data)
{
in_user = !strcmp(r.key, "user"); in_user = !strcmp(r.key, "user");
}
else if (r.depth == 3 && in_user) else if (r.depth == 3 && in_user)
{ {
if (!strcmp(r.key, "id" )) r.NextStrDup(&userId); if (!strcmp(r.key, "id" ))
else if (!strcmp(r.key, "username" )) r.NextStrDup(&username); r.NextStrDup(&userId);
else if (!strcmp(r.key, "avatar" )) r.NextStrDup(&avatar); else if (!strcmp(r.key, "username" ))
else if (!strcmp(r.key, "discriminator")) r.NextStrDup(&discriminator); r.NextStrDup(&username);
else if (!strcmp(r.key, "avatar" ))
r.NextStrDup(&avatar);
else if (!strcmp(r.key, "discriminator"))
r.NextStrDup(&discriminator);
} }
} }
@ -398,10 +332,14 @@ extern "C" void Discord_Initialize(
WasJustConnected.exchange(true); WasJustConnected.exchange(true);
ReconnectTimeMs.reset(); ReconnectTimeMs.reset();
if (userId ) free(userId ); if (userId)
if (username ) free(username ); free(userId);
if (avatar ) free(avatar ); if (username)
if (discriminator) free(discriminator); free(username);
if (avatar)
free(avatar);
if (discriminator)
free(discriminator);
}; };
Connection->onDisconnect = [](int err, const char* message) Connection->onDisconnect = [](int err, const char* message)
{ {
@ -412,10 +350,8 @@ extern "C" void Discord_Initialize(
Handlers = {}; Handlers = {};
} }
WasJustDisconnected.exchange(true); WasJustDisconnected.exchange(true);
UpdateReconnectTime(); update_reconnect_time();
}; };
IoThread->Start();
} }
extern "C" void Discord_Shutdown(void) extern "C" void Discord_Shutdown(void)
@ -425,25 +361,16 @@ extern "C" void Discord_Shutdown(void)
Connection->onConnect = nullptr; Connection->onConnect = nullptr;
Connection->onDisconnect = nullptr; Connection->onDisconnect = nullptr;
Handlers = {}; Handlers = {};
if (IoThread)
{
IoThread->Stop();
delete IoThread;
IoThread = nullptr;
}
RpcConnection::Destroy(Connection); RpcConnection::Destroy(Connection);
} }
extern "C" void Discord_UpdatePresence(const DiscordRichPresence* presence) extern "C" void Discord_UpdatePresence(const DiscordRichPresence* presence)
{
{ {
std::lock_guard<std::mutex> guard(PresenceMutex); std::lock_guard<std::mutex> guard(PresenceMutex);
QueuedPresence.length = JsonWriteRichPresenceObj( QueuedPresence.length = JsonWriteRichPresenceObj(
QueuedPresence.buffer, sizeof(QueuedPresence.buffer), Nonce++, Pid, presence); QueuedPresence.buffer, sizeof(QueuedPresence.buffer),
} Nonce++, Pid, presence);
if (IoThread)
IoThread->Notify();
} }
extern "C" void Discord_ClearPresence(void) extern "C" void Discord_ClearPresence(void)
@ -451,7 +378,8 @@ extern "C" void Discord_ClearPresence(void)
Discord_UpdatePresence(nullptr); Discord_UpdatePresence(nullptr);
} }
extern "C" void Discord_Respond(const char* userId, /* DISCORD_REPLY_ */ int reply) extern "C" void Discord_Respond(const char* userId,
/* DISCORD_REPLY_ */ int reply)
{ {
/* if we are not connected, let's not batch up stale messages for later */ /* if we are not connected, let's not batch up stale messages for later */
if (!Connection || !Connection->IsOpen()) if (!Connection || !Connection->IsOpen())
@ -462,8 +390,6 @@ extern "C" void Discord_Respond(const char* userId, /* DISCORD_REPLY_ */ int rep
qmessage->length = qmessage->length =
JsonWriteJoinReply(qmessage->buffer, sizeof(qmessage->buffer), userId, reply, Nonce++); JsonWriteJoinReply(qmessage->buffer, sizeof(qmessage->buffer), userId, reply, Nonce++);
SendQueue.CommitAdd(); SendQueue.CommitAdd();
if (IoThread)
IoThread->Notify();
} }
} }
@ -531,14 +457,12 @@ extern "C" void Discord_RunCallbacks(void)
while (JoinAskQueue.HavePendingSends()) while (JoinAskQueue.HavePendingSends())
{ {
auto req = JoinAskQueue.GetNextSendMessage(); auto req = JoinAskQueue.GetNextSendMessage();
{
std::lock_guard<std::mutex> guard(HandlerMutex); std::lock_guard<std::mutex> guard(HandlerMutex);
if (Handlers.joinRequest) if (Handlers.joinRequest)
{ {
DiscordUser du{req->userId, req->username, req->discriminator, req->avatar}; DiscordUser du{req->userId, req->username, req->discriminator, req->avatar};
Handlers.joinRequest(&du); Handlers.joinRequest(&du);
} }
}
JoinAskQueue.CommitSend(); JoinAskQueue.CommitSend();
} }

View File

@ -324,6 +324,7 @@ static void frontend_psp_exec(const char *path, bool should_load_game)
#endif #endif
char argp[512] = {0}; char argp[512] = {0};
SceSize args = 0; SceSize args = 0;
int ret;
#if !defined(VITA) #if !defined(VITA)
strlcpy(argp, eboot_path, sizeof(argp)); strlcpy(argp, eboot_path, sizeof(argp));
@ -346,21 +347,25 @@ static void frontend_psp_exec(const char *path, bool should_load_game)
sceAppMgrGetAppParam(boot_params); sceAppMgrGetAppParam(boot_params);
if (strstr(boot_params,"psgm:play")) if (strstr(boot_params,"psgm:play"))
{ {
int ret; char *param1 = strstr(boot_params, "&param=");
char *param1 = strstr(boot_params, "&param=")+7;
char *param2 = strstr(boot_params, "&param2="); char *param2 = strstr(boot_params, "&param2=");
if (param1 != NULL && param2 != NULL)
{
param1 += 7;
memcpy(core_name, param1, param2 - param1); memcpy(core_name, param1, param2 - param1);
core_name[param2-param1] = 0; core_name[param2-param1] = 0;
sprintf(argp, param2 + 8); sprintf(argp, param2 + 8);
ret = sceAppMgrLoadExec(core_name, (char * const*)((const char*[]){argp, 0}), NULL); ret = sceAppMgrLoadExec(core_name, (char * const*)((const char*[]){argp, 0}), NULL);
RARCH_LOG("Attempt to load executable: [%d].\n", ret); RARCH_LOG("Attempt to load executable: [%d].\n", ret);
goto exit;
}
RARCH_LOG("Required boot params missing. Continue nornal boot.");
} }
else
#endif #endif
{ ret = sceAppMgrLoadExec(path, args == 0 ? NULL : (char * const*)((const char*[]){argp, 0}), NULL);
int ret = sceAppMgrLoadExec(path, args == 0 ? NULL : (char * const*)((const char*[]){argp, 0}), NULL);
RARCH_LOG("Attempt to load executable: [%d].\n", ret); RARCH_LOG("Attempt to load executable: [%d].\n", ret);
} exit:
return;
#else #else
exitspawn_kernel(path, args, argp); exitspawn_kernel(path, args, argp);
#endif #endif

View File

@ -1054,6 +1054,13 @@ static LRESULT CALLBACK wnd_proc_common_dinput_internal(HWND hwnd,
keysym |= 0x80; keysym |= 0x80;
keycode = input_keymaps_translate_keysym_to_rk(keysym); keycode = input_keymaps_translate_keysym_to_rk(keysym);
switch (keycode)
{
/* L+R Shift handling done in dinput_poll */
case RETROK_LSHIFT:
case RETROK_RSHIFT:
return 0;
}
input_keyboard_event(keydown, keycode, input_keyboard_event(keydown, keycode,
0, mod, RETRO_DEVICE_KEYBOARD); 0, mod, RETRO_DEVICE_KEYBOARD);

View File

@ -600,8 +600,10 @@ bool slang_reflect(
} }
else if (index == SLANG_INVALID_TEXTURE_SEMANTIC) else if (index == SLANG_INVALID_TEXTURE_SEMANTIC)
{ {
RARCH_ERR("[slang]: Non-semantic textures not supported yet, " RARCH_ERR("[slang]: Texture name '%s' not found in semantic map, "
"Probably a texture name or pass alias is not found. \n"); "Probably the texture name or pass alias is not defined "
"in the preset (Non-semantic textures not supported yet)\n",
fragment.sampled_images[i].name.c_str());
return false; return false;
} }

View File

@ -802,21 +802,29 @@ static bool font_init_first(
* Neutral : * Neutral :
* 0020 - 002F : 001xxxxx (c & 0xE0) == 0x20 * 0020 - 002F : 001xxxxx (c & 0xE0) == 0x20
* Arabic: * Arabic:
* 0600 - 07FF : 11011xxx (c & 0xF8) == 0xD8 (2 bytes) * 0600 - 06FF : 110110xx (c & 0xFC) == 0xD8 (2 bytes) */
* 0800 - 08FF : 11100000 101000xx c == 0xE0 && (c1 & 0xAC) == 0xA0 (3 bytes) */
/* clang-format off */ /* clang-format off */
#define IS_ASCII(p) ((*(p)&0x80) == 0x00) #define IS_ASCII(p) ((*(p)&0x80) == 0x00)
#define IS_MBSTART(p) ((*(p)&0xC0) == 0xC0) #define IS_MBSTART(p) ((*(p)&0xC0) == 0xC0)
#define IS_MBCONT(p) ((*(p)&0xC0) == 0x80) #define IS_MBCONT(p) ((*(p)&0xC0) == 0x80)
#define IS_DIR_NEUTRAL(p) ((*(p)&0xE0) == 0x20) #define IS_DIR_NEUTRAL(p) ((*(p)&0xE0) == 0x20)
#define IS_ARABIC0(p) ((*(p)&0xF8) == 0xD8) #define IS_ARABIC(p) ((*(p)&0xFC) == 0xD8)
#define IS_ARABIC1(p) ((*(p) == 0xE0) && ((*((p) + 1) & 0xAC) == 0xA0))
#define IS_ARABIC(p) (IS_ARABIC0(p) || IS_ARABIC1(p))
#define IS_RTL(p) IS_ARABIC(p) #define IS_RTL(p) IS_ARABIC(p)
#define GET_ID_ARABIC(p) (((unsigned char)(p)[0] << 6) | ((unsigned char)(p)[1] & 0x3F))
/* 0x0620 to 0x064F */ /* 0x0620 to 0x064F */
static const unsigned arabic_shape_map[0x50 - 0x20][0x4] = { static const unsigned arabic_shape_map[0x100][0x4] = {
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x0600 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x0610 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, /* 0x0620 */ { 0 }, /* 0x0620 */
{ 0xFE80 }, { 0xFE80 },
{ 0xFE81, 0xFE82 }, { 0xFE81, 0xFE82 },
@ -843,99 +851,189 @@ static const unsigned arabic_shape_map[0x50 - 0x20][0x4] = {
{ 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC }, { 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC },
{ 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0 }, { 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0 },
{ 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4 }, { 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4 },
{ 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8 },
{ 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8 },
{ 0xFEC9, 0xFECA, 0xFECB, 0xFECC }, { 0xFEC9, 0xFECA, 0xFECB, 0xFECC },
{ 0xFECD, 0xFECE, 0xFECF, 0xFED0 }, { 0xFECD, 0xFECE, 0xFECF, 0xFED0 },
{ 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, { 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0xFED1, 0xFED2, 0xFED3, 0xFED4 }, /* 0x0640 */ { 0 }, /* 0x0640 */
{ 0xFED1, 0xFED2, 0xFED3, 0xFED4 },
{ 0xFED5, 0xFED6, 0xFED7, 0xFED8 }, { 0xFED5, 0xFED6, 0xFED7, 0xFED8 },
{ 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC }, { 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC },
{ 0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0 }, { 0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0 },
{ 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4 }, { 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4 },
{ 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8 }, { 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8 },
{ 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC }, { 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC },
{ 0xFEED, 0xFEEE },
{ 0xFEED, 0xFEEE },
{ 0xFEEF, 0xFEF0, 0xFBE8, 0xFBE9 }, { 0xFEEF, 0xFEF0, 0xFBE8, 0xFBE9 },
{ 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4 }, { 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4 },
{ 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x0650 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x0660 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x0670 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 },
{ 0xFB56, 0xFB57, 0xFB58, 0xFB59 },
{ 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x0680 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x0690 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x06A0 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 },
{ 0xFB8E, 0xFB8F, 0xFB90, 0xFB91 },
{ 0 }, { 0 },
{ 0 }, { 0 }, { 0 },
{ 0xFB92, 0xFB93, 0xFB94, 0xFB95 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x06B0 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x06C0 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF },
{ 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x06D0 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x06E0 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x06F0 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
}; };
/* clang-format on */ /* clang-format on */
static INLINE unsigned font_get_replacement(const char* src, const char* start) static INLINE unsigned font_get_replacement(const char* src, const char* start)
{ {
if ((*src & 0xFC) == 0xD8) /* 0x0600 to 0x06FF */ if (IS_ARABIC(src)) /* 0x0600 to 0x06FF */
{ {
unsigned result = 0; unsigned result = 0;
bool prev_connected = false; bool prev_connected = false;
bool next_connected = false; bool next_connected = false;
unsigned char id = ((unsigned char)src[0] << 6) | ((unsigned char)src[1] & 0x3F); unsigned char id = GET_ID_ARABIC(src);
const char* prev1 = src - 2; const char* prev = src - 2;
const char* prev2 = src - 4; const char* next = src + 2;
if (id < 0x21 || id > 0x4A) if ((prev >= start) && IS_ARABIC(prev))
return 0;
if (prev2 < start)
{ {
prev2 = NULL; unsigned char prev_id = GET_ID_ARABIC(prev);
if (prev1 < start)
prev1 = NULL; /* nonspacing diacritics 0x4b -- 0x5f */
while (prev_id > 0x4A && prev_id < 0x60)
{
prev -= 2;
if ((prev >= start) && IS_ARABIC(prev))
prev_id = GET_ID_ARABIC(prev);
else
break;
} }
if (prev1 && (*prev1 & 0xFC) == 0xD8)
{
unsigned char prev1_id = 0;
if (prev1) if (prev_id == 0x44) /* Arabic Letter Lam */
prev1_id = ((unsigned char)prev1[0] << 6) | ((unsigned char)prev1[1] & 0x3F);
if (prev1_id == 0x44)
{ {
unsigned char prev2_id = 0; unsigned char prev2_id = 0;
const char* prev2 = prev - 2;
if (prev2) if (prev2 >= start)
prev2_id = (prev2[0] << 6) | (prev2[1] & 0x3F); prev2_id = (prev2[0] << 6) | (prev2[1] & 0x3F);
if (prev2_id > 0x20 || prev2_id < 0x50) /* nonspacing diacritics 0x4b -- 0x5f */
prev_connected = !!arabic_shape_map[prev2_id - 0x20][2]; while (prev2_id > 0x4A && prev2_id < 0x60)
{
prev2 -= 2;
if ((prev2 >= start) && IS_ARABIC(prev2))
prev2_id = GET_ID_ARABIC(prev2);
else
break;
}
prev_connected = !!arabic_shape_map[prev2_id][2];
switch (id) switch (id)
{ {
case 0x22: case 0x22: /* Arabic Letter Alef with Madda Above */
return 0xFEF5 + prev_connected; return 0xFEF5 + prev_connected;
case 0x23: case 0x23: /* Arabic Letter Alef with Hamza Above */
return 0xFEF7 + prev_connected; return 0xFEF7 + prev_connected;
case 0x25: case 0x25: /* Arabic Letter Alef with Hamza Below */
return 0xFEF9 + prev_connected; return 0xFEF9 + prev_connected;
case 0x27: case 0x27: /* Arabic Letter Alef */
return 0xFEFB + prev_connected; return 0xFEFB + prev_connected;
} }
} }
if (prev1_id > 0x20 || prev1_id < 0x50) prev_connected = !!arabic_shape_map[prev_id][2];
prev_connected = !!arabic_shape_map[prev1_id - 0x20][2];
} }
if ((src[2] & 0xFC) == 0xD8) if (IS_ARABIC(next))
{ {
unsigned char next_id = ((unsigned char)src[2] << 6) | ((unsigned char)src[3] & 0x3F); unsigned char next_id = GET_ID_ARABIC(next);
if (next_id > 0x20 || next_id < 0x50) /* nonspacing diacritics 0x4b -- 0x5f */
next_connected = true; while (next_id > 0x4A && next_id < 0x60)
{
next += 2;
if (IS_ARABIC(next))
next_id = GET_ID_ARABIC(next);
else
break;
} }
result = arabic_shape_map[id - 0x20][prev_connected | (next_connected << 1)]; next_connected = !!arabic_shape_map[next_id][1];
}
result = arabic_shape_map[id][prev_connected | (next_connected << 1)];
if (result) if (result)
return result; return result;
return arabic_shape_map[id - 0x20][prev_connected]; return arabic_shape_map[id][prev_connected];
} }
return 0; return 0;
@ -961,22 +1059,17 @@ static char* font_driver_reshape_msg(const char* msg, unsigned char *buffer, siz
if (reverse) if (reverse)
{ {
src--; src--;
while (IS_MBCONT(src)) while (src > (const unsigned char*)msg && IS_MBCONT(src))
{
src--; src--;
if (src == (const unsigned char*)msg) if (src >= (const unsigned char*)msg && (IS_RTL(src) || IS_DIR_NEUTRAL(src)))
goto end;
}
if (IS_RTL(src) || IS_DIR_NEUTRAL(src))
{ {
unsigned replacement = font_get_replacement((const char*)src, msg); unsigned replacement = font_get_replacement((const char*)src, msg);
if (replacement) if (replacement)
{ {
if (replacement < 0x80) if (replacement < 0x80)
*dst++ = replacement; *dst++ = replacement;
else if (replacement < 0x8000) else if (replacement < 0x800)
{ {
*dst++ = 0xC0 | (replacement >> 6); *dst++ = 0xC0 | (replacement >> 6);
*dst++ = 0x80 | (replacement & 0x3F); *dst++ = 0x80 | (replacement & 0x3F);
@ -1030,7 +1123,7 @@ static char* font_driver_reshape_msg(const char* msg, unsigned char *buffer, siz
*dst++ = *src++; *dst++ = *src++;
} }
} }
end:
*dst = '\0'; *dst = '\0';
return (char*)dst_buffer; return (char*)dst_buffer;

View File

@ -282,6 +282,7 @@ extern const struct softfilter_implementation *scale2x_get_implementation(softfi
extern const struct softfilter_implementation *normal2x_get_implementation(softfilter_simd_mask_t simd); extern const struct softfilter_implementation *normal2x_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *normal2x_width_get_implementation(softfilter_simd_mask_t simd); extern const struct softfilter_implementation *normal2x_width_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *normal2x_height_get_implementation(softfilter_simd_mask_t simd); extern const struct softfilter_implementation *normal2x_height_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *normal4x_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *scanline2x_get_implementation(softfilter_simd_mask_t simd); extern const struct softfilter_implementation *scanline2x_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *grid2x_get_implementation(softfilter_simd_mask_t simd); extern const struct softfilter_implementation *grid2x_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *grid3x_get_implementation(softfilter_simd_mask_t simd); extern const struct softfilter_implementation *grid3x_get_implementation(softfilter_simd_mask_t simd);
@ -304,6 +305,7 @@ static const softfilter_get_implementation_t soft_plugs_builtin[] = {
normal2x_get_implementation, normal2x_get_implementation,
normal2x_width_get_implementation, normal2x_width_get_implementation,
normal2x_height_get_implementation, normal2x_height_get_implementation,
normal4x_get_implementation,
scanline2x_get_implementation, scanline2x_get_implementation,
grid2x_get_implementation, grid2x_get_implementation,
grid3x_get_implementation, grid3x_get_implementation,

View File

@ -70,7 +70,7 @@ endif
objects += blargg_ntsc_snes.$(DYLIB) phosphor2x.$(DYLIB) epx.$(DYLIB) lq2x.$(DYLIB) \ objects += blargg_ntsc_snes.$(DYLIB) phosphor2x.$(DYLIB) epx.$(DYLIB) lq2x.$(DYLIB) \
2xsai.$(DYLIB) super2xsai.$(DYLIB) supereagle.$(DYLIB) 2xbr.$(DYLIB) \ 2xsai.$(DYLIB) super2xsai.$(DYLIB) supereagle.$(DYLIB) 2xbr.$(DYLIB) \
darken.$(DYLIB) scale2x.$(DYLIB) normal2x.$(DYLIB) \ darken.$(DYLIB) scale2x.$(DYLIB) normal2x.$(DYLIB) \
normal2x_width.$(DYLIB) normal2x_height.$(DYLIB) \ normal2x_width.$(DYLIB) normal2x_height.$(DYLIB) normal4x.$(DYLIB) \
scanline2x.$(DYLIB) grid2x.$(DYLIB) grid3x.$(DYLIB) \ scanline2x.$(DYLIB) grid2x.$(DYLIB) grid3x.$(DYLIB) \
gameboy3x.$(DYLIB) gameboy4x.$(DYLIB) \ gameboy3x.$(DYLIB) gameboy4x.$(DYLIB) \
dot_matrix_3x.$(DYLIB) dot_matrix_4x.$(DYLIB) dot_matrix_3x.$(DYLIB) dot_matrix_4x.$(DYLIB)

View File

@ -0,0 +1 @@
filter = normal4x

View File

@ -0,0 +1,255 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2011-2018 - Daniel De Matteis
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
/* Compile: gcc -o normal4x.so -shared normal4x.c -std=c99 -O3 -Wall -pedantic -fPIC */
#include "softfilter.h"
#include <stdlib.h>
#include <string.h>
#ifdef RARCH_INTERNAL
#define softfilter_get_implementation normal4x_get_implementation
#define softfilter_thread_data normal4x_softfilter_thread_data
#define filter_data normal4x_filter_data
#endif
struct softfilter_thread_data
{
void *out_data;
const void *in_data;
size_t out_pitch;
size_t in_pitch;
unsigned colfmt;
unsigned width;
unsigned height;
int first;
int last;
};
struct filter_data
{
unsigned threads;
struct softfilter_thread_data *workers;
unsigned in_fmt;
};
static unsigned normal4x_generic_input_fmts(void)
{
return SOFTFILTER_FMT_XRGB8888 | SOFTFILTER_FMT_RGB565;
}
static unsigned normal4x_generic_output_fmts(unsigned input_fmts)
{
return input_fmts;
}
static unsigned normal4x_generic_threads(void *data)
{
struct filter_data *filt = (struct filter_data*)data;
return filt->threads;
}
static void *normal4x_generic_create(const struct softfilter_config *config,
unsigned in_fmt, unsigned out_fmt,
unsigned max_width, unsigned max_height,
unsigned threads, softfilter_simd_mask_t simd, void *userdata)
{
struct filter_data *filt = (struct filter_data*)calloc(1, sizeof(*filt));
(void)simd;
(void)config;
(void)userdata;
if (!filt) {
return NULL;
}
/* Apparently the code is not thread-safe,
* so force single threaded operation... */
filt->workers = (struct softfilter_thread_data*)calloc(1, sizeof(struct softfilter_thread_data));
filt->threads = 1;
filt->in_fmt = in_fmt;
if (!filt->workers) {
free(filt);
return NULL;
}
return filt;
}
static void normal4x_generic_output(void *data,
unsigned *out_width, unsigned *out_height,
unsigned width, unsigned height)
{
*out_width = width << 2;
*out_height = height << 2;
}
static void normal4x_generic_destroy(void *data)
{
struct filter_data *filt = (struct filter_data*)data;
if (!filt) {
return;
}
free(filt->workers);
free(filt);
}
static void normal4x_work_cb_xrgb8888(void *data, void *thread_data)
{
struct softfilter_thread_data *thr = (struct softfilter_thread_data*)thread_data;
const uint32_t *input = (const uint32_t*)thr->in_data;
uint32_t *output = (uint32_t*)thr->out_data;
uint32_t in_stride = (uint32_t)(thr->in_pitch >> 2);
uint32_t out_stride = (uint32_t)(thr->out_pitch >> 2);
uint32_t x, y;
for (y = 0; y < thr->height; ++y)
{
uint32_t *out_ptr = output;
for (x = 0; x < thr->width; ++x)
{
uint32_t *out_line_ptr = out_ptr;
uint32_t color = *(input + x);
uint32_t row_color[4];
row_color[0] = color;
row_color[1] = color;
row_color[2] = color;
row_color[3] = color;
/* Row 1 */
memcpy(out_line_ptr, row_color, sizeof(row_color));
out_line_ptr += out_stride;
/* Row 2 */
memcpy(out_line_ptr, row_color, sizeof(row_color));
out_line_ptr += out_stride;
/* Row 3 */
memcpy(out_line_ptr, row_color, sizeof(row_color));
out_line_ptr += out_stride;
/* Row 4 */
memcpy(out_line_ptr, row_color, sizeof(row_color));
out_ptr += 4;
}
input += in_stride;
output += out_stride << 2;
}
}
static void normal4x_work_cb_rgb565(void *data, void *thread_data)
{
struct softfilter_thread_data *thr = (struct softfilter_thread_data*)thread_data;
const uint16_t *input = (const uint16_t*)thr->in_data;
uint16_t *output = (uint16_t*)thr->out_data;
uint16_t in_stride = (uint16_t)(thr->in_pitch >> 1);
uint16_t out_stride = (uint16_t)(thr->out_pitch >> 1);
uint16_t x, y;
for (y = 0; y < thr->height; ++y)
{
uint16_t *out_ptr = output;
for (x = 0; x < thr->width; ++x)
{
uint16_t *out_line_ptr = out_ptr;
uint16_t color = *(input + x);
uint16_t row_color[4];
row_color[0] = color;
row_color[1] = color;
row_color[2] = color;
row_color[3] = color;
/* Row 1 */
memcpy(out_line_ptr, row_color, sizeof(row_color));
out_line_ptr += out_stride;
/* Row 2 */
memcpy(out_line_ptr, row_color, sizeof(row_color));
out_line_ptr += out_stride;
/* Row 3 */
memcpy(out_line_ptr, row_color, sizeof(row_color));
out_line_ptr += out_stride;
/* Row 4 */
memcpy(out_line_ptr, row_color, sizeof(row_color));
out_ptr += 4;
}
input += in_stride;
output += out_stride << 2;
}
}
static void normal4x_generic_packets(void *data,
struct softfilter_work_packet *packets,
void *output, size_t output_stride,
const void *input, unsigned width, unsigned height, size_t input_stride)
{
/* We are guaranteed single threaded operation
* (filt->threads = 1) so we don't need to loop
* over threads and can cull some code. This only
* makes the tiniest performance difference, but
* every little helps when running on an o3DS... */
struct filter_data *filt = (struct filter_data*)data;
struct softfilter_thread_data *thr = (struct softfilter_thread_data*)&filt->workers[0];
thr->out_data = (uint8_t*)output;
thr->in_data = (const uint8_t*)input;
thr->out_pitch = output_stride;
thr->in_pitch = input_stride;
thr->width = width;
thr->height = height;
if (filt->in_fmt == SOFTFILTER_FMT_XRGB8888) {
packets[0].work = normal4x_work_cb_xrgb8888;
} else if (filt->in_fmt == SOFTFILTER_FMT_RGB565) {
packets[0].work = normal4x_work_cb_rgb565;
}
packets[0].thread_data = thr;
}
static const struct softfilter_implementation normal4x_generic = {
normal4x_generic_input_fmts,
normal4x_generic_output_fmts,
normal4x_generic_create,
normal4x_generic_destroy,
normal4x_generic_threads,
normal4x_generic_output,
normal4x_generic_packets,
SOFTFILTER_API_VERSION,
"Normal4x",
"normal4x",
};
const struct softfilter_implementation *softfilter_get_implementation(
softfilter_simd_mask_t simd)
{
(void)simd;
return &normal4x_generic;
}
#ifdef RARCH_INTERNAL
#undef softfilter_get_implementation
#undef softfilter_thread_data
#undef filter_data
#endif

View File

@ -38,7 +38,7 @@ RETRO_BEGIN_DECLS
#endif #endif
#ifndef GFX_MAX_PARAMETERS #ifndef GFX_MAX_PARAMETERS
#define GFX_MAX_PARAMETERS 256 #define GFX_MAX_PARAMETERS 512
#endif #endif
#ifndef GFX_MAX_FRAME_HISTORY #ifndef GFX_MAX_FRAME_HISTORY

View File

@ -1003,6 +1003,7 @@ FILTERS
#include "../gfx/video_filters/normal2x.c" #include "../gfx/video_filters/normal2x.c"
#include "../gfx/video_filters/normal2x_width.c" #include "../gfx/video_filters/normal2x_width.c"
#include "../gfx/video_filters/normal2x_height.c" #include "../gfx/video_filters/normal2x_height.c"
#include "../gfx/video_filters/normal4x.c"
#include "../gfx/video_filters/scanline2x.c" #include "../gfx/video_filters/scanline2x.c"
#include "../gfx/video_filters/grid2x.c" #include "../gfx/video_filters/grid2x.c"
#include "../gfx/video_filters/grid3x.c" #include "../gfx/video_filters/grid3x.c"

View File

@ -81,6 +81,7 @@ struct dinput_input
int mouse_x; int mouse_x;
int mouse_y; int mouse_y;
uint8_t state[256]; uint8_t state[256];
bool shift_l, shift_r, alt_l;
bool doubleclick_on_titlebar; bool doubleclick_on_titlebar;
bool mouse_l, mouse_r, mouse_m, mouse_b4, mouse_b5, mouse_wu, mouse_wd, mouse_hwu, mouse_hwd; bool mouse_l, mouse_r, mouse_m, mouse_b4, mouse_b5, mouse_wu, mouse_wd, mouse_hwu, mouse_hwd;
}; };
@ -160,7 +161,7 @@ static void *dinput_init(const char *joypad_driver)
{ {
IDirectInputDevice8_SetDataFormat(di->keyboard, &c_dfDIKeyboard); IDirectInputDevice8_SetDataFormat(di->keyboard, &c_dfDIKeyboard);
IDirectInputDevice8_SetCooperativeLevel(di->keyboard, IDirectInputDevice8_SetCooperativeLevel(di->keyboard,
(HWND)video_driver_window_get(), DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); (HWND)video_driver_window_get(), DISCL_NONEXCLUSIVE | DISCL_FOREGROUND | DISCL_NOWINKEY);
IDirectInputDevice8_Acquire(di->keyboard); IDirectInputDevice8_Acquire(di->keyboard);
} }
@ -181,6 +182,50 @@ static void *dinput_init(const char *joypad_driver)
return di; return di;
} }
static void dinput_keyboard_mods(struct dinput_input *di, int mod)
{
switch (mod)
{
case RETROKMOD_SHIFT:
{
unsigned vk_shift_l = GetAsyncKeyState(VK_LSHIFT) >> 1;
unsigned vk_shift_r = GetAsyncKeyState(VK_RSHIFT) >> 1;
if ( (vk_shift_l && !di->shift_l) ||
(!vk_shift_l && di->shift_l))
{
input_keyboard_event(vk_shift_l, RETROK_LSHIFT,
0, RETROKMOD_SHIFT, RETRO_DEVICE_KEYBOARD);
di->shift_l = !di->shift_l;
}
if ( (vk_shift_r && !di->shift_r) ||
(!vk_shift_r && di->shift_r))
{
input_keyboard_event(vk_shift_r, RETROK_RSHIFT,
0, RETROKMOD_SHIFT, RETRO_DEVICE_KEYBOARD);
di->shift_r = !di->shift_r;
}
}
break;
case RETROKMOD_ALT:
{
unsigned vk_alt_l = GetAsyncKeyState(VK_LMENU) >> 1;
if (vk_alt_l && !di->alt_l)
di->alt_l = !di->alt_l;
else if (!vk_alt_l && di->alt_l)
{
input_keyboard_event(vk_alt_l, RETROK_LALT,
0, RETROKMOD_ALT, RETRO_DEVICE_KEYBOARD);
di->alt_l = !di->alt_l;
}
}
break;
}
}
static void dinput_poll(void *data) static void dinput_poll(void *data)
{ {
struct dinput_input *di = (struct dinput_input*)data; struct dinput_input *di = (struct dinput_input*)data;
@ -211,6 +256,12 @@ static void dinput_poll(void *data)
*kb_state = 0; *kb_state = 0;
} }
} }
else
/* Shifts only when window focused */
dinput_keyboard_mods(di, RETROKMOD_SHIFT);
/* Left alt keyup when unfocused, to prevent alt-tab sticky */
dinput_keyboard_mods(di, RETROKMOD_ALT);
} }
if (di->mouse) if (di->mouse)

View File

@ -117,6 +117,7 @@ enum
RARCH_RECORDING_TOGGLE, RARCH_RECORDING_TOGGLE,
RARCH_STREAMING_TOGGLE, RARCH_STREAMING_TOGGLE,
RARCH_RUNAHEAD_TOGGLE,
RARCH_AI_SERVICE, RARCH_AI_SERVICE,

View File

@ -225,6 +225,10 @@ int msg_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len)
snprintf(s, len, snprintf(s, len,
"Toggle between recording and not."); "Toggle between recording and not.");
break; break;
case RARCH_RUNAHEAD_TOGGLE:
snprintf(s, len,
"Toggles Run-Ahead mode on/off.");
break;
default: default:
if (string_is_empty(s)) if (string_is_empty(s))
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len); strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len);

View File

@ -2555,6 +2555,14 @@ MSG_HASH(
MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE,
"Starts/stops streaming of the current session to an online video platform." "Starts/stops streaming of the current session to an online video platform."
) )
MSG_HASH(
MENU_ENUM_LABEL_VALUE_INPUT_META_RUNAHEAD_TOGGLE,
"Run-Ahead (Toggle)"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_INPUT_META_RUNAHEAD_TOGGLE,
"Switches Run-Ahead on/off."
)
MSG_HASH( MSG_HASH(
MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE, MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE,
"AI Service" "AI Service"
@ -11276,6 +11284,18 @@ MSG_HASH(
MSG_CORE_REMAP_FILE_LOADED, MSG_CORE_REMAP_FILE_LOADED,
"Core remap file loaded." "Core remap file loaded."
) )
MSG_HASH(
MSG_RUNAHEAD_ENABLED,
"Run-Ahead enabled. Latency frames removed: %u."
)
MSG_HASH(
MSG_RUNAHEAD_ENABLED_WITH_SECOND_INSTANCE,
"Run-Ahead enabled with Secondary Instance. Latency frames removed: %u."
)
MSG_HASH(
MSG_RUNAHEAD_DISABLED,
"Run-Ahead disabled."
)
MSG_HASH( MSG_HASH(
MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES, MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES,
"Run-Ahead has been disabled because this core does not support save states." "Run-Ahead has been disabled because this core does not support save states."

View File

@ -1104,11 +1104,7 @@ void config_set_string(config_file_t *conf, const char *key, const char *val)
if (entry) if (entry)
{ {
/* An entry corresponding to 'key' already exists /* An entry corresponding to 'key' already exists
* > Check if it's read only */ * > Check whether value is currently set */
if (entry->readonly)
return;
/* Check whether value is currently set */
if (entry->value) if (entry->value)
{ {
/* Do nothing if value is unchanged */ /* Do nothing if value is unchanged */
@ -1120,8 +1116,11 @@ void config_set_string(config_file_t *conf, const char *key, const char *val)
free(entry->value); free(entry->value);
} }
/* Update value */ /* Update value
* > Note that once a value is set, it
* is no longer considered 'read only' */
entry->value = strdup(val); entry->value = strdup(val);
entry->readonly = false;
conf->modified = true; conf->modified = true;
return; return;
} }
@ -1300,14 +1299,6 @@ void config_file_dump_orbis(config_file_t *conf, int fd)
if (conf->reference) if (conf->reference)
fprintf(file, "#reference \"%s\"\n", conf->reference); fprintf(file, "#reference \"%s\"\n", conf->reference);
while (includes)
{
char cad[256];
snprintf(cad, sizeof(cad),
"#include %s\n", includes->path);
orbisWrite(fd, cad, strlen(cad));
includes = includes->next;
}
list = config_file_merge_sort_linked_list( list = config_file_merge_sort_linked_list(
(struct config_entry_list*)conf->entries, (struct config_entry_list*)conf->entries,
@ -1325,6 +1316,21 @@ void config_file_dump_orbis(config_file_t *conf, int fd)
} }
list = list->next; list = list->next;
} }
/* Config files are read from the top down - if
* duplicate entries are found then the topmost
* one in the list takes precedence. This means
* '#include' directives must go *after* individual
* config entries, otherwise they will override
* any custom-set values */
while (includes)
{
char cad[256];
snprintf(cad, sizeof(cad),
"#include %s\n", includes->path);
orbisWrite(fd, cad, strlen(cad));
includes = includes->next;
}
} }
#endif #endif
@ -1336,12 +1342,6 @@ void config_file_dump(config_file_t *conf, FILE *file, bool sort)
if (conf->reference) if (conf->reference)
fprintf(file, "#reference \"%s\"\n", conf->reference); fprintf(file, "#reference \"%s\"\n", conf->reference);
while (includes)
{
fprintf(file, "#include \"%s\"\n", includes->path);
includes = includes->next;
}
if (sort) if (sort)
list = config_file_merge_sort_linked_list( list = config_file_merge_sort_linked_list(
(struct config_entry_list*)conf->entries, (struct config_entry_list*)conf->entries,
@ -1357,6 +1357,18 @@ void config_file_dump(config_file_t *conf, FILE *file, bool sort)
fprintf(file, "%s = \"%s\"\n", list->key, list->value); fprintf(file, "%s = \"%s\"\n", list->key, list->value);
list = list->next; list = list->next;
} }
/* Config files are read from the top down - if
* duplicate entries are found then the topmost
* one in the list takes precedence. This means
* '#include' directives must go *after* individual
* config entries, otherwise they will override
* any custom-set values */
while (includes)
{
fprintf(file, "#include \"%s\"\n", includes->path);
includes = includes->next;
}
} }
bool config_entry_exists(config_file_t *conf, const char *entry) bool config_entry_exists(config_file_t *conf, const char *entry)

View File

@ -66,11 +66,16 @@
*------------------------------------------------- *-------------------------------------------------
*/ */
/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
#define LZMA_MIN_ALIGNMENT_BITS 512
#define LZMA_MIN_ALIGNMENT_BYTES (LZMA_MIN_ALIGNMENT_BITS / 8)
static void *lzma_fast_alloc(void *p, size_t size) static void *lzma_fast_alloc(void *p, size_t size)
{ {
int scan; int scan;
uint32_t *addr = NULL; uint32_t *addr = NULL;
lzma_allocator *codec = (lzma_allocator *)(p); lzma_allocator *codec = (lzma_allocator *)(p);
uintptr_t vaddr = 0;
/* compute the size, rounding to the nearest 1k */ /* compute the size, rounding to the nearest 1k */
size = (size + 0x3ff) & ~0x3ff; size = (size + 0x3ff) & ~0x3ff;
@ -83,27 +88,36 @@ static void *lzma_fast_alloc(void *p, size_t size)
{ {
/* set the low bit of the size so we don't match next time */ /* set the low bit of the size so we don't match next time */
*ptr |= 1; *ptr |= 1;
return ptr + 1;
/* return aligned address of the block */
return codec->allocptr2[scan];
} }
} }
/* alloc a new one and put it into the list */ /* alloc a new one and put it into the list */
addr = (uint32_t *)malloc(sizeof(uint32_t) * size + sizeof(uintptr_t)); addr = (uint32_t *)malloc(size + sizeof(uint32_t) + LZMA_MIN_ALIGNMENT_BYTES);
if (!addr) if (addr==NULL)
return NULL; return NULL;
for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
{ {
if (codec->allocptr[scan] == NULL) if (codec->allocptr[scan] == NULL)
{ {
/* store block address */
codec->allocptr[scan] = addr; codec->allocptr[scan] = addr;
/* compute aligned address, store it */
vaddr = (uintptr_t)addr;
vaddr = (vaddr + sizeof(uint32_t) + (LZMA_MIN_ALIGNMENT_BYTES-1)) & (~(LZMA_MIN_ALIGNMENT_BYTES-1));
codec->allocptr2[scan] = (uint32_t*)vaddr;
break; break;
} }
} }
/* set the low bit of the size so we don't match next time */ /* set the low bit of the size so we don't match next time */
*addr = (uint32_t)(size | 1); *addr = size | 1;
return addr + (sizeof(uint32_t) == sizeof(uintptr_t) ? 1 : 2);
/* return aligned address */
return (void*)vaddr;
} }
/*------------------------------------------------- /*-------------------------------------------------
@ -114,21 +128,22 @@ static void *lzma_fast_alloc(void *p, size_t size)
static void lzma_fast_free(void *p, void *address) static void lzma_fast_free(void *p, void *address)
{ {
int scan; int scan;
uint32_t *ptr; uint32_t *ptr = NULL;
lzma_allocator *codec; lzma_allocator *codec = NULL;
if (address == NULL) if (address == NULL)
return; return;
codec = (lzma_allocator *)(p); codec = (lzma_allocator *)(p);
/* find the hunk */ /* find the hunk */
ptr = (uint32_t *)(address) - 1; ptr = (uint32_t *)address;
for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
{ {
if (ptr == codec->allocptr[scan]) if (ptr == codec->allocptr2[scan])
{ {
/* clear the low bit of the size to allow matches */ /* clear the low bit of the size to allow matches */
*ptr &= ~1; *codec->allocptr[scan] &= ~1;
return; return;
} }
} }

View File

@ -241,9 +241,14 @@ chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t comple
allocates and frees memory frequently allocates and frees memory frequently
-------------------------------------------------*/ -------------------------------------------------*/
/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
#define ZLIB_MIN_ALIGNMENT_BITS 512
#define ZLIB_MIN_ALIGNMENT_BYTES (ZLIB_MIN_ALIGNMENT_BITS / 8)
voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
{ {
zlib_allocator *alloc = (zlib_allocator *)opaque; zlib_allocator *alloc = (zlib_allocator *)opaque;
uintptr_t paddr = 0;
UINT32 *ptr; UINT32 *ptr;
int i; int i;
@ -258,12 +263,14 @@ voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
{ {
/* set the low bit of the size so we don't match next time */ /* set the low bit of the size so we don't match next time */
*ptr |= 1; *ptr |= 1;
return ptr + 1;
/* return aligned block address */
return (voidpf)(alloc->allocptr2[i]);
} }
} }
/* alloc a new one */ /* alloc a new one */
ptr = (UINT32 *)malloc(size + sizeof(uintptr_t)); ptr = (UINT32 *)malloc(size + sizeof(UINT32) + ZLIB_MIN_ALIGNMENT_BYTES);
if (!ptr) if (!ptr)
return NULL; return NULL;
@ -272,12 +279,16 @@ voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
if (!alloc->allocptr[i]) if (!alloc->allocptr[i])
{ {
alloc->allocptr[i] = ptr; alloc->allocptr[i] = ptr;
paddr = (((uintptr_t)ptr) + sizeof(UINT32) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1));
alloc->allocptr2[i] = (uint32_t*)paddr;
break; break;
} }
/* set the low bit of the size so we don't match next time */ /* set the low bit of the size so we don't match next time */
*ptr = size | 1; *ptr = size | 1;
return ptr + (sizeof(uint32_t) == sizeof(uintptr_t) ? 1 : 2);
/* return aligned block address */
return (voidpf)paddr;
} }
/*------------------------------------------------- /*-------------------------------------------------
@ -288,15 +299,15 @@ voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
void zlib_fast_free(voidpf opaque, voidpf address) void zlib_fast_free(voidpf opaque, voidpf address)
{ {
zlib_allocator *alloc = (zlib_allocator *)opaque; zlib_allocator *alloc = (zlib_allocator *)opaque;
UINT32 *ptr = (UINT32 *)address - (sizeof(uint32_t) == sizeof(uintptr_t) ? 1 : 2); UINT32 *ptr = (UINT32 *)address;
int i; int i;
/* find the hunk */ /* find the hunk */
for (i = 0; i < MAX_ZLIB_ALLOCS; i++) for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
if (ptr == alloc->allocptr[i]) if (ptr == alloc->allocptr2[i])
{ {
/* clear the low bit of the size to allow matches */ /* clear the low bit of the size to allow matches */
*ptr &= ~1; *(alloc->allocptr[i]) &= ~1;
return; return;
} }
} }

View File

@ -143,16 +143,6 @@ rxml_document_t *rxml_load_document_string(const char *str)
if (!doc) if (!doc)
goto error; goto error;
doc->root_node = (struct rxml_node *)malloc(
sizeof(*doc->root_node));
doc->root_node->name = NULL;
doc->root_node->data = NULL;
doc->root_node->attrib = NULL;
doc->root_node->children = NULL;
doc->root_node->next = NULL;
yxml_init(&x, buf->xml, BUFSIZE); yxml_init(&x, buf->xml, BUFSIZE);
for (; *str; ++str) for (; *str; ++str)
@ -256,30 +246,14 @@ rxml_document_t *rxml_load_document_string(const char *str)
case YXML_ATTRSTART: case YXML_ATTRSTART:
if (attr) if (attr)
{ attr = attr->next = (struct rxml_attrib_node*)
struct rxml_attrib_node
*new_node = (struct rxml_attrib_node*)
calloc(1, sizeof(*attr)); calloc(1, sizeof(*attr));
attr = new_node;
attr->next = new_node ;
}
else else
{ attr = node->attrib = (struct rxml_attrib_node*)calloc(1, sizeof(*attr));
struct rxml_attrib_node
*new_node = (struct rxml_attrib_node*)
calloc(1, sizeof(*attr));
attr = new_node;
if (node)
node->attrib = new_node;
}
if (attr)
{
if (attr->attrib) if (attr->attrib)
free(attr->attrib); free(attr->attrib);
attr->attrib = strdup(x.attr); attr->attrib = strdup(x.attr);
}
valptr = buf->val; valptr = buf->val;
break; break;

View File

@ -27,6 +27,7 @@ typedef struct _zlib_allocator zlib_allocator;
struct _zlib_allocator struct _zlib_allocator
{ {
UINT32 * allocptr[MAX_ZLIB_ALLOCS]; UINT32 * allocptr[MAX_ZLIB_ALLOCS];
UINT32 * allocptr2[MAX_ZLIB_ALLOCS];
}; };
typedef struct _zlib_codec_data zlib_codec_data; typedef struct _zlib_codec_data zlib_codec_data;

View File

@ -30,6 +30,7 @@ struct _lzma_allocator
void (*Free)(void *p, void *address); /* address can be 0 */ void (*Free)(void *p, void *address); /* address can be 0 */
void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */ void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */
uint32_t* allocptr[MAX_LZMA_ALLOCS]; uint32_t* allocptr[MAX_LZMA_ALLOCS];
uint32_t* allocptr2[MAX_LZMA_ALLOCS];
}; };
typedef struct _lzma_codec_data lzma_codec_data; typedef struct _lzma_codec_data lzma_codec_data;

View File

@ -269,6 +269,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_game_focus_toggle, ME
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_ui_companion_toggle, MENU_ENUM_SUBLABEL_INPUT_META_UI_COMPANION_TOGGLE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_ui_companion_toggle, MENU_ENUM_SUBLABEL_INPUT_META_UI_COMPANION_TOGGLE)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_recording_toggle, MENU_ENUM_SUBLABEL_INPUT_META_RECORDING_TOGGLE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_recording_toggle, MENU_ENUM_SUBLABEL_INPUT_META_RECORDING_TOGGLE)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_streaming_toggle, MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_streaming_toggle, MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_runahead_toggle, MENU_ENUM_SUBLABEL_INPUT_META_RUNAHEAD_TOGGLE)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_ai_service, MENU_ENUM_SUBLABEL_INPUT_META_AI_SERVICE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_ai_service, MENU_ENUM_SUBLABEL_INPUT_META_AI_SERVICE)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_menu_toggle, MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_menu_toggle, MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_hotkey_block_delay, MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BLOCK_DELAY) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_hotkey_block_delay, MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BLOCK_DELAY)
@ -1694,6 +1695,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case RARCH_STREAMING_TOGGLE: case RARCH_STREAMING_TOGGLE:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_streaming_toggle); BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_streaming_toggle);
return 0; return 0;
case RARCH_RUNAHEAD_TOGGLE:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_runahead_toggle);
return 0;
case RARCH_AI_SERVICE: case RARCH_AI_SERVICE:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_ai_service); BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_ai_service);
return 0; return 0;

View File

@ -459,6 +459,9 @@ enum msg_hash_enums
MSG_GAME_REMAP_FILE_LOADED, MSG_GAME_REMAP_FILE_LOADED,
MSG_DIRECTORY_REMAP_FILE_LOADED, MSG_DIRECTORY_REMAP_FILE_LOADED,
MSG_CORE_REMAP_FILE_LOADED, MSG_CORE_REMAP_FILE_LOADED,
MSG_RUNAHEAD_ENABLED,
MSG_RUNAHEAD_ENABLED_WITH_SECOND_INSTANCE,
MSG_RUNAHEAD_DISABLED,
MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES, MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES,
MSG_RUNAHEAD_FAILED_TO_SAVE_STATE, MSG_RUNAHEAD_FAILED_TO_SAVE_STATE,
MSG_RUNAHEAD_FAILED_TO_LOAD_STATE, MSG_RUNAHEAD_FAILED_TO_LOAD_STATE,
@ -851,6 +854,7 @@ enum msg_hash_enums
MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE,
MENU_ENUM_LABEL_VALUE_INPUT_META_RECORDING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORDING_TOGGLE,
MENU_ENUM_LABEL_VALUE_INPUT_META_STREAMING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_STREAMING_TOGGLE,
MENU_ENUM_LABEL_VALUE_INPUT_META_RUNAHEAD_TOGGLE,
MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE, MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE,
MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE,
@ -903,6 +907,7 @@ enum msg_hash_enums
MENU_ENUM_SUBLABEL_INPUT_META_UI_COMPANION_TOGGLE, MENU_ENUM_SUBLABEL_INPUT_META_UI_COMPANION_TOGGLE,
MENU_ENUM_SUBLABEL_INPUT_META_RECORDING_TOGGLE, MENU_ENUM_SUBLABEL_INPUT_META_RECORDING_TOGGLE,
MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE,
MENU_ENUM_SUBLABEL_INPUT_META_RUNAHEAD_TOGGLE,
MENU_ENUM_SUBLABEL_INPUT_META_AI_SERVICE, MENU_ENUM_SUBLABEL_INPUT_META_AI_SERVICE,
MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE, MENU_ENUM_SUBLABEL_INPUT_META_MENU_TOGGLE,

View File

@ -24,6 +24,7 @@
android:isGame="true" android:isGame="true"
android:banner="@drawable/banner" android:banner="@drawable/banner"
android:extractNativeLibs="true" android:extractNativeLibs="true"
android:requestLegacyExternalStorage="true"
tools:ignore="UnusedAttribute"> tools:ignore="UnusedAttribute">
<activity android:name="com.retroarch.browser.mainmenu.MainMenuActivity" android:exported="true" android:launchMode="singleInstance"> <activity android:name="com.retroarch.browser.mainmenu.MainMenuActivity" android:exported="true" android:launchMode="singleInstance">
<intent-filter> <intent-filter>

View File

@ -25,8 +25,8 @@ allprojects {
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
compileSdkVersion 28 compileSdkVersion 29
buildToolsVersion "28.0.3" buildToolsVersion "29.0.3"
flavorDimensions "variant" flavorDimensions "variant"
@ -37,7 +37,7 @@ android {
arguments "-j${Runtime.runtime.availableProcessors()}" arguments "-j${Runtime.runtime.availableProcessors()}"
} }
} }
targetSdkVersion 28 targetSdkVersion 29
} }
productFlavors { productFlavors {

View File

@ -1,10 +1,10 @@
apply plugin: 'com.android.dynamic-feature' apply plugin: 'com.android.dynamic-feature'
android { android {
compileSdkVersion 28 compileSdkVersion 29
defaultConfig { defaultConfig {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 28 targetSdkVersion 29
} }
flavorDimensions "variant" flavorDimensions "variant"

View File

@ -85,6 +85,8 @@ HAVE_VIVANTE_FBDEV=no # Vivante fbdev context support
HAVE_OPENDINGUX_FBDEV=no # Opendingux fbdev context support HAVE_OPENDINGUX_FBDEV=no # Opendingux fbdev context support
HAVE_OPENGLES=no # Use GLESv2 instead of desktop GL HAVE_OPENGLES=no # Use GLESv2 instead of desktop GL
HAVE_OPENGLES3=no # OpenGLES3 support HAVE_OPENGLES3=no # OpenGLES3 support
HAVE_OPENGLES3_1=no # OpenGLES3.1 support
HAVE_OPENGLES3_2=no # OpenGLES3.2 support
HAVE_X11=auto # everything X11. HAVE_X11=auto # everything X11.
HAVE_XRANDR=auto # Xrandr support. HAVE_XRANDR=auto # Xrandr support.
HAVE_OMAP=no # OMAP video support HAVE_OMAP=no # OMAP video support
@ -187,3 +189,4 @@ C89_METAL=no
HAVE_NETWORK_VIDEO=no HAVE_NETWORK_VIDEO=no
HAVE_STEAM=no # Enable Steam build HAVE_STEAM=no # Enable Steam build
HAVE_ODROIDGO2=no # ODROID-GO Advance rotation support (requires librga) HAVE_ODROIDGO2=no # ODROID-GO Advance rotation support (requires librga)
HAVE_GIT_VERSION=yes # Git version support

View File

@ -2730,6 +2730,7 @@ static const struct input_bind_map input_config_bind_map[RARCH_BIND_LIST_END_NUL
#endif #endif
DECLARE_META_BIND(2, recording_toggle, RARCH_RECORDING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORDING_TOGGLE), DECLARE_META_BIND(2, recording_toggle, RARCH_RECORDING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORDING_TOGGLE),
DECLARE_META_BIND(2, streaming_toggle, RARCH_STREAMING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_STREAMING_TOGGLE), DECLARE_META_BIND(2, streaming_toggle, RARCH_STREAMING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_STREAMING_TOGGLE),
DECLARE_META_BIND(2, runahead_toggle, RARCH_RUNAHEAD_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_RUNAHEAD_TOGGLE),
DECLARE_META_BIND(2, ai_service, RARCH_AI_SERVICE, MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE), DECLARE_META_BIND(2, ai_service, RARCH_AI_SERVICE, MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE),
}; };
@ -12982,6 +12983,7 @@ static const struct cmd_map map[] = {
{ "MENU_TOGGLE", RARCH_MENU_TOGGLE }, { "MENU_TOGGLE", RARCH_MENU_TOGGLE },
{ "RECORDING_TOGGLE", RARCH_RECORDING_TOGGLE }, { "RECORDING_TOGGLE", RARCH_RECORDING_TOGGLE },
{ "STREAMING_TOGGLE", RARCH_STREAMING_TOGGLE }, { "STREAMING_TOGGLE", RARCH_STREAMING_TOGGLE },
{ "RUNAHEAD_TOGGLE", RARCH_RUNAHEAD_TOGGLE },
{ "MENU_UP", RETRO_DEVICE_ID_JOYPAD_UP }, { "MENU_UP", RETRO_DEVICE_ID_JOYPAD_UP },
{ "MENU_DOWN", RETRO_DEVICE_ID_JOYPAD_DOWN }, { "MENU_DOWN", RETRO_DEVICE_ID_JOYPAD_DOWN },
{ "MENU_LEFT", RETRO_DEVICE_ID_JOYPAD_LEFT }, { "MENU_LEFT", RETRO_DEVICE_ID_JOYPAD_LEFT },
@ -15993,6 +15995,37 @@ bool command_event(enum event_command cmd, void *data)
command_event(CMD_EVENT_RECORD_INIT, NULL); command_event(CMD_EVENT_RECORD_INIT, NULL);
} }
break; break;
case CMD_EVENT_RUNAHEAD_TOGGLE:
settings->bools.run_ahead_enabled = !(settings->bools.run_ahead_enabled);
char msg[256];
msg[0] = '\0';
if (!settings->bools.run_ahead_enabled)
{
runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_DISABLED),
1, 100, false,
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
else if (!settings->bools.run_ahead_secondary_instance)
{
snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_RUNAHEAD_ENABLED),
settings->uints.run_ahead_frames);
runloop_msg_queue_push(
msg, 1, 100, false,
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
else
{
snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_RUNAHEAD_ENABLED_WITH_SECOND_INSTANCE),
settings->uints.run_ahead_frames);
runloop_msg_queue_push(
msg, 1, 100, false,
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
break;
case CMD_EVENT_RECORDING_TOGGLE: case CMD_EVENT_RECORDING_TOGGLE:
if (recording_is_enabled()) if (recording_is_enabled())
command_event(CMD_EVENT_RECORD_DEINIT, NULL); command_event(CMD_EVENT_RECORD_DEINIT, NULL);
@ -18846,6 +18879,22 @@ static bool dynamic_request_hw_context(enum retro_hw_context_type type,
#if defined(HAVE_OPENGLES3) #if defined(HAVE_OPENGLES3)
case RETRO_HW_CONTEXT_OPENGLES_VERSION: case RETRO_HW_CONTEXT_OPENGLES_VERSION:
#ifndef HAVE_OPENGLES3_2
if (major == 3 && minor == 2)
{
RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch is compiled against a lesser version. Cannot use HW context.\n",
major, minor);
return false;
}
#endif
#if !defined(HAVE_OPENGLES3_2) && !defined(HAVE_OPENGLES3_1)
if (major == 3 && minor == 1)
{
RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch is compiled against a lesser version. Cannot use HW context.\n",
major, minor);
return false;
}
#endif
RARCH_LOG("Requesting OpenGLES%u.%u context.\n", RARCH_LOG("Requesting OpenGLES%u.%u context.\n",
major, minor); major, minor);
break; break;
@ -24504,9 +24553,12 @@ static void input_driver_poll(void)
unsigned remap_button = unsigned remap_button =
settings->uints.input_keymapper_ids[i][j]; settings->uints.input_keymapper_ids[i][j];
bool remap_valid = bool remap_valid =
remap_button != RETROK_UNKNOWN; remap_button != RETROK_UNKNOWN &&
if (remap_valid) !handle->keys[remap_button / 32];
{
if (!remap_valid)
continue;
unsigned current_button_value = unsigned current_button_value =
BIT256_GET_PTR(p_new_state, j); BIT256_GET_PTR(p_new_state, j);
@ -24538,7 +24590,6 @@ static void input_driver_poll(void)
remap_button, remap_button,
0, 0, RETRO_DEVICE_KEYBOARD); 0, 0, RETRO_DEVICE_KEYBOARD);
} }
}
break; break;
/* gamepad remapping */ /* gamepad remapping */
@ -39679,12 +39730,15 @@ static enum runloop_state runloop_check_state(
/* Check if we have pressed the recording toggle button */ /* Check if we have pressed the recording toggle button */
HOTKEY_CHECK(RARCH_RECORDING_TOGGLE, CMD_EVENT_RECORDING_TOGGLE, true, NULL); HOTKEY_CHECK(RARCH_RECORDING_TOGGLE, CMD_EVENT_RECORDING_TOGGLE, true, NULL);
/* Check if we have pressed the AI Service toggle button */
HOTKEY_CHECK(RARCH_AI_SERVICE, CMD_EVENT_AI_SERVICE_TOGGLE, true, NULL);
/* Check if we have pressed the streaming toggle button */ /* Check if we have pressed the streaming toggle button */
HOTKEY_CHECK(RARCH_STREAMING_TOGGLE, CMD_EVENT_STREAMING_TOGGLE, true, NULL); HOTKEY_CHECK(RARCH_STREAMING_TOGGLE, CMD_EVENT_STREAMING_TOGGLE, true, NULL);
/* Check if we have pressed the Run-Ahead toggle button */
HOTKEY_CHECK(RARCH_RUNAHEAD_TOGGLE, CMD_EVENT_RUNAHEAD_TOGGLE, true, NULL);
/* Check if we have pressed the AI Service toggle button */
HOTKEY_CHECK(RARCH_AI_SERVICE, CMD_EVENT_AI_SERVICE_TOGGLE, true, NULL);
if (BIT256_GET(current_bits, RARCH_VOLUME_UP)) if (BIT256_GET(current_bits, RARCH_VOLUME_UP))
command_event(CMD_EVENT_VOLUME_UP, NULL); command_event(CMD_EVENT_VOLUME_UP, NULL);
else if (BIT256_GET(current_bits, RARCH_VOLUME_DOWN)) else if (BIT256_GET(current_bits, RARCH_VOLUME_DOWN))

View File

@ -708,10 +708,15 @@ static int database_info_list_iterate_found_match(
const char *archive_name const char *archive_name
) )
{ {
char db_crc[PATH_MAX_LENGTH]; /* TODO/FIXME - heap allocations are done here to avoid
char db_playlist_base_str[PATH_MAX_LENGTH]; * running out of stack space on systems with a limited stack size.
char db_playlist_path[PATH_MAX_LENGTH]; * We should use less fullsize paths in the future so that we don't
char entry_path_str[PATH_MAX_LENGTH]; * need to have all these big char arrays here */
size_t str_len = PATH_MAX_LENGTH * sizeof(char);
char* db_crc = (char*)malloc(str_len);
char* db_playlist_base_str = (char*)malloc(str_len);
char* db_playlist_path = (char*)malloc(str_len);
char* entry_path_str = (char*)malloc(str_len);
char *hash = NULL; char *hash = NULL;
playlist_t *playlist = NULL; playlist_t *playlist = NULL;
const char *db_path = const char *db_path =
@ -727,25 +732,25 @@ static int database_info_list_iterate_found_match(
entry_path_str[0] = '\0'; entry_path_str[0] = '\0';
fill_short_pathname_representation_noext(db_playlist_base_str, fill_short_pathname_representation_noext(db_playlist_base_str,
db_path, sizeof(db_playlist_base_str)); db_path, str_len);
strlcat(db_playlist_base_str, ".lpl", sizeof(db_playlist_base_str)); strlcat(db_playlist_base_str, ".lpl", str_len);
if (!string_is_empty(_db->playlist_directory)) if (!string_is_empty(_db->playlist_directory))
fill_pathname_join(db_playlist_path, _db->playlist_directory, fill_pathname_join(db_playlist_path, _db->playlist_directory,
db_playlist_base_str, sizeof(db_playlist_path)); db_playlist_base_str, str_len);
playlist_config_set_path(&_db->playlist_config, db_playlist_path); playlist_config_set_path(&_db->playlist_config, db_playlist_path);
playlist = playlist_init(&_db->playlist_config); playlist = playlist_init(&_db->playlist_config);
snprintf(db_crc, sizeof(db_crc), "%08X|crc", db_info_entry->crc32); snprintf(db_crc, str_len, "%08X|crc", db_info_entry->crc32);
if (entry_path) if (entry_path)
strlcpy(entry_path_str, entry_path, sizeof(entry_path_str)); strlcpy(entry_path_str, entry_path, str_len);
if (!string_is_empty(archive_name)) if (!string_is_empty(archive_name))
fill_pathname_join_delim(entry_path_str, fill_pathname_join_delim(entry_path_str,
entry_path_str, archive_name, '#', sizeof(entry_path_str)); entry_path_str, archive_name, '#', str_len);
if (core_info_database_match_archive_member( if (core_info_database_match_archive_member(
db_state->list->elems[db_state->list_index].data) && db_state->list->elems[db_state->list_index].data) &&
@ -826,6 +831,10 @@ static int database_info_list_iterate_found_match(
db_state->list->elems[0] = entry; db_state->list->elems[0] = entry;
} }
free(db_crc);
free(db_playlist_base_str);
free(db_playlist_path);
free(entry_path_str);
return 0; return 0;
} }

View File

@ -860,7 +860,11 @@ static void task_load_handler(retro_task_t *task)
{ {
if (state->autoload) if (state->autoload)
{ {
#ifdef __CELLOS_LV2__
char *msg = (char*)malloc(8192 * sizeof(char));
#else
char msg[8192]; char msg[8192];
#endif
msg[0] = '\0'; msg[0] = '\0';
@ -871,6 +875,9 @@ static void task_load_handler(retro_task_t *task)
state->path, state->path,
msg_hash_to_str(MSG_FAILED)); msg_hash_to_str(MSG_FAILED));
task_set_error(task, strdup(msg)); task_set_error(task, strdup(msg));
#ifdef __CELLOS_LV2__
free(msg);
#endif
} }
else else
task_set_error(task, strdup(msg_hash_to_str(MSG_FAILED_TO_LOAD_STATE))); task_set_error(task, strdup(msg_hash_to_str(MSG_FAILED_TO_LOAD_STATE)));

View File

@ -141,7 +141,7 @@ void PlaylistEntryDialog::loadPlaylistOptions()
QString ui_display_name; QString ui_display_name;
QHash<QString, QString> hash; QHash<QString, QString> hash;
const core_info_t *core = &core_info_list->list[i]; const core_info_t *core = &core_info_list->list[i];
QStringList databases = QString(core->databases).split("|"); QStringList databases = string_split_to_qt(QString(core->databases), '|');
hash["core_name"] = core->core_name; hash["core_name"] = core->core_name;
hash["core_display_name"] = core->display_name; hash["core_display_name"] = core->display_name;
@ -278,8 +278,7 @@ const QStringList PlaylistEntryDialog::getSelectedExtensions()
/* Otherwise it would create a QStringList with a single blank entry... */ /* Otherwise it would create a QStringList with a single blank entry... */
if (!text.isEmpty()) if (!text.isEmpty())
list = text.split(' '); list = string_split_to_qt(text, ' ');
return list; return list;
} }

View File

@ -8,6 +8,7 @@
#include <QButtonGroup> #include <QButtonGroup>
#include "settingswidgets.h" #include "settingswidgets.h"
#include "../ui_qt.h"
#include <math.h> #include <math.h>
@ -442,7 +443,7 @@ StringComboBox::StringComboBox(rarch_setting_t *setting, QWidget *parent) :
,m_setting(setting) ,m_setting(setting)
,m_value(setting->value.target.string) ,m_value(setting->value.target.string)
{ {
addItems(QString(setting->values).split("|")); addItems(string_split_to_qt(QString(setting->values), '|'));
connect(this, SIGNAL(currentTextChanged(const QString&)), this, SLOT(onCurrentTextChanged(const QString&))); connect(this, SIGNAL(currentTextChanged(const QString&)), this, SLOT(onCurrentTextChanged(const QString&)));

View File

@ -16,6 +16,7 @@
*/ */
#include "ui_qt_load_core_window.h" #include "ui_qt_load_core_window.h"
#include "../ui_qt.h"
#include <QFileDialog> #include <QFileDialog>
#include <QDesktopWidget> #include <QDesktopWidget>
@ -235,8 +236,7 @@ void LoadCoreWindow::initCoreList(const QStringList &extensionFilters)
name_item = new QTableWidgetItem(name); name_item = new QTableWidgetItem(name);
hash["path"] = core->path; hash["path"] = core->path;
hash["extensions"] = QString( hash["extensions"] = string_split_to_qt(QString(core->supported_extensions), '|');
core->supported_extensions).split("|");
name_item->setData(Qt::UserRole, hash); name_item->setData(Qt::UserRole, hash);
name_item->setFlags(name_item->flags() & ~Qt::ItemIsEditable); name_item->setFlags(name_item->flags() & ~Qt::ItemIsEditable);

View File

@ -764,3 +764,26 @@ ui_companion_driver_t ui_companion_qt = {
&ui_application_qt, &ui_application_qt,
"qt", "qt",
}; };
QStringList string_split_to_qt(QString str, char delim)
{
int at;
QStringList list = QStringList();
for (at = 0;;)
{
/* Find next split */
int spl = str.indexOf(delim, at);
/* Store split into list of extensions */
list << str.mid(at, (spl < 0 ? -1 : spl - at));
/* No more splits */
if (spl < 0)
break;
at = spl + 1;
}
return list;
}

View File

@ -678,6 +678,8 @@ typedef struct ui_window_qt
MainWindow *qtWindow; MainWindow *qtWindow;
} ui_window_qt_t; } ui_window_qt_t;
QStringList string_split_to_qt(QString str, char delim);
RETRO_END_DECLS RETRO_END_DECLS
#endif #endif