(SoftFilter) Refactor most code associated to SoftFilter plugin - load .filt

files instead of the dynamic libraries directly. Options can be
set in the config file.

There's still a problem with config file options - will work this
out later.
This commit is contained in:
twinaphex 2014-08-19 19:38:33 +02:00
parent 0bd97eb1ba
commit 4dea8caa6f
35 changed files with 457 additions and 885 deletions

View File

@ -1311,10 +1311,8 @@ void rarch_init_filter(enum retro_pixel_format colfmt)
struct retro_game_geometry *geom = NULL;
rarch_deinit_filter();
#ifndef HAVE_FILTERS_BUILTIN
if (!*g_settings.video.filter_path)
if (!*g_settings.video.softfilter_plugin)
return;
#endif
// Deprecated format. Gets pre-converted.
if (colfmt == RETRO_PIXEL_FORMAT_0RGB1555)
@ -1333,7 +1331,7 @@ void rarch_init_filter(enum retro_pixel_format colfmt)
pow2_y = 0;
maxsize = 0;
g_extern.filter.filter = rarch_softfilter_new(g_settings.video.filter_path,
g_extern.filter.filter = rarch_softfilter_new(g_settings.video.softfilter_plugin,
RARCH_SOFTFILTER_THREADS_AUTO, colfmt, width, height);
if (!g_extern.filter.filter)

View File

@ -615,23 +615,6 @@ extern const menu_ctx_driver_t menu_ctx_lakka;
extern const menu_ctx_driver_backend_t menu_ctx_backend_common;
extern const menu_ctx_driver_backend_t menu_ctx_backend_lakka;
#ifdef HAVE_FILTERS_BUILTIN
extern const struct softfilter_implementation *blargg_ntsc_snes_rf_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *blargg_ntsc_snes_composite_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *blargg_ntsc_snes_svideo_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *blargg_ntsc_snes_rgb_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *lq2x_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *phosphor2x_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *twoxbr_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *epx_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *twoxsai_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *supereagle_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *supertwoxsai_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *twoxbr_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *darken_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *scale2x_get_implementation(softfilter_simd_mask_t simd);
#endif
static inline bool input_key_pressed_func(int key)
{
bool ret = false;

View File

@ -1655,7 +1655,7 @@ static void menu_parse_and_resolve(unsigned menu_type)
else if (menu_common_type_is(menu_type) == MENU_SETTINGS_SHADER_OPTIONS)
exts = "cg|glsl";
else if (menu_type == MENU_SETTINGS_VIDEO_SOFTFILTER)
exts = EXT_EXECUTABLES;
exts = "filt";
else if (menu_type == MENU_SETTINGS_AUDIO_DSP_FILTER)
exts = "dsp";
else if (menu_type == MENU_SETTINGS_OVERLAY_PRESET)
@ -3286,41 +3286,8 @@ static int menu_common_setting_set(unsigned id, unsigned action, rarch_setting_t
menu_common_setting_set_current_path_selection(setting, "", id, action);
break;
case MENU_SETTINGS_VIDEO_SOFTFILTER:
switch (action)
{
#if defined(HAVE_DYLIB)
case MENU_ACTION_OK:
menu_common_setting_push_current_menu(
driver.menu->menu_stack,
g_settings.video.filter_dir, id,
driver.menu->selection_ptr, action);
break;
case MENU_ACTION_START:
strlcpy(g_settings.video.filter_path, "", sizeof(g_settings.video.filter_path));
driver.menu_data_own = true;
rarch_main_command(RARCH_CMD_REINIT);
break;
#elif defined(HAVE_FILTERS_BUILTIN)
case MENU_ACTION_LEFT:
if (g_settings.video.filter_idx > 0)
g_settings.video.filter_idx--;
break;
case MENU_ACTION_RIGHT:
if ((g_settings.video.filter_idx + 1) != softfilter_get_last_idx())
g_settings.video.filter_idx++;
break;
case MENU_ACTION_OK:
driver.menu_data_own = true;
rarch_main_command(RARCH_CMD_REINIT);
driver.menu->need_refresh = true;
break;
case MENU_ACTION_START:
g_settings.video.filter_idx = 0;
driver.menu_data_own = true;
rarch_main_command(RARCH_CMD_REINIT);
break;
#endif
}
if (setting)
menu_common_setting_set_current_path_selection(setting, g_settings.video.filter_dir, id, action);
break;
case MENU_SETTINGS_AUDIO_DSP_FILTER:
if (setting)
@ -4220,10 +4187,7 @@ static void menu_common_setting_set_label(char *type_str, size_t type_str_size,
strlcpy(type_str, "...", type_str_size);
break;
case MENU_SETTINGS_VIDEO_SOFTFILTER:
{
const char *filter_name = rarch_softfilter_get_name(g_extern.filter.filter);
strlcpy(type_str, filter_name ? filter_name : "N/A", type_str_size);
}
strlcpy(type_str, path_basename(g_settings.video.softfilter_plugin), type_str_size);
break;
case MENU_SETTINGS_AUDIO_DSP_FILTER:
strlcpy(type_str, path_basename(g_settings.audio.dsp_plugin), type_str_size);

View File

@ -219,10 +219,7 @@ struct settings
char shader_path[PATH_MAX];
bool shader_enable;
#ifdef HAVE_FILTERS_BUILTIN
unsigned filter_idx;
#endif
char filter_path[PATH_MAX];
char softfilter_plugin[PATH_MAX];
float refresh_rate;
bool threaded;

View File

@ -16,17 +16,24 @@
#include "filter.h"
#include "filters/softfilter.h"
#include "../dynamic.h"
#include "../conf/config_file.h"
#include "../general.h"
#include "../file_path.h"
#include "../file_ext.h"
#include "../performance.h"
#include <stdlib.h>
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#ifdef HAVE_THREADS
#include "../thread.h"
struct rarch_soft_plug
{
#ifdef HAVE_DYLIB
dylib_t lib;
#endif
const struct softfilter_implementation *impl;
};
struct filter_thread_data
{
sthread_t *thread;
@ -66,13 +73,14 @@ static void filter_thread_loop(void *data)
struct rarch_softfilter
{
#if !defined(HAVE_FILTERS_BUILTIN) && defined(HAVE_DYLIB)
dylib_t lib;
#endif
config_file_t *conf;
const struct softfilter_implementation *impl;
void *impl_data;
struct rarch_soft_plug *plugs;
unsigned num_plugs;
unsigned max_width, max_height;
enum retro_pixel_format pix_fmt, out_pix_fmt;
@ -84,110 +92,157 @@ struct rarch_softfilter
#endif
};
#ifdef HAVE_FILTERS_BUILTIN
static const struct softfilter_implementation *(*softfilter_drivers[]) (softfilter_simd_mask_t) =
const struct softfilter_implementation *softfilter_find_implementation(rarch_softfilter_t *filt, const char *ident)
{
NULL,
&blargg_ntsc_snes_rf_get_implementation,
&blargg_ntsc_snes_composite_get_implementation,
&blargg_ntsc_snes_svideo_get_implementation,
&blargg_ntsc_snes_rgb_get_implementation,
&lq2x_get_implementation,
&phosphor2x_get_implementation,
&twoxbr_get_implementation,
&darken_get_implementation,
&twoxsai_get_implementation,
&supertwoxsai_get_implementation,
&supereagle_get_implementation,
&epx_get_implementation,
&scale2x_get_implementation,
unsigned i;
for (i = 0; i < filt->num_plugs; i++)
{
if (!strcmp(filt->plugs[i].impl->short_ident, ident))
return filt->plugs[i].impl;
}
return NULL;
}
struct softfilter_userdata
{
config_file_t *conf;
const char *prefix[2];
};
unsigned softfilter_get_last_idx(void)
static int softfilter_get_float(void *userdata, const char *key_str, float *value, float default_value)
{
return sizeof(softfilter_drivers) / sizeof(softfilter_drivers[0]);
struct softfilter_userdata *filt = (struct softfilter_userdata*)userdata;
char key[2][256];
snprintf(key[0], sizeof(key[0]), "%s_%s", filt->prefix[0], key_str);
snprintf(key[1], sizeof(key[1]), "%s_%s", filt->prefix[1], key_str);
bool got = config_get_float(filt->conf, key[0], value);
got = got || config_get_float(filt->conf, key[1], value);
if (!got)
*value = default_value;
return got;
}
static softfilter_get_implementation_t softfilter_get_implementation_from_idx(unsigned i)
static int softfilter_get_int(void *userdata, const char *key_str, int *value, int default_value)
{
if (i < softfilter_get_last_idx())
return softfilter_drivers[i];
return NULL;
struct softfilter_userdata *filt = (struct softfilter_userdata*)userdata;
char key[2][256];
snprintf(key[0], sizeof(key[0]), "%s_%s", filt->prefix[0], key_str);
snprintf(key[1], sizeof(key[1]), "%s_%s", filt->prefix[1], key_str);
bool got = config_get_int(filt->conf, key[0], value);
got = got || config_get_int(filt->conf, key[1], value);
if (!got)
*value = default_value;
return got;
}
#endif
#define softfilter_get_array_setup() \
struct softfilter_userdata *filt = (struct softfilter_userdata*)userdata; \
\
char key[2][256]; \
snprintf(key[0], sizeof(key[0]), "%s_%s", filt->prefix[0], key_str); \
snprintf(key[1], sizeof(key[1]), "%s_%s", filt->prefix[1], key_str); \
\
char *str = NULL; \
bool got = config_get_string(filt->conf, key[0], &str); \
got = got || config_get_string(filt->conf, key[1], &str);
const char *rarch_softfilter_get_name(void *data)
{
(void)data;
#ifdef HAVE_FILTERS_BUILTIN
unsigned cpu_features;
const struct softfilter_implementation *impl;
softfilter_get_implementation_t cb = (softfilter_get_implementation_t)softfilter_get_implementation_from_idx(g_settings.video.filter_idx);
if (cb)
{
cpu_features = rarch_get_cpu_features();
impl = (const struct softfilter_implementation *)cb(cpu_features);
if (impl)
return impl->ident;
#define softfilter_get_array_body(T) \
if (got) \
{ \
unsigned i; \
struct string_list *list = string_split(str, " "); \
*values = (T*)calloc(list->size, sizeof(T)); \
for (i = 0; i < list->size; i++) \
(*values)[i] = (T)strtod(list->elems[i].data, NULL); \
*out_num_values = list->size; \
string_list_free(list); \
return true; \
} \
else \
{ \
*values = (T*)calloc(num_default_values, sizeof(T)); \
memcpy(*values, default_values, sizeof(T) * num_default_values); \
*out_num_values = num_default_values; \
return false; \
}
return NULL;
#else
rarch_softfilter_t *filt = (rarch_softfilter_t*)data;
if (!filt || !filt->impl)
return NULL;
return filt->impl->ident;
#endif
static int softfilter_get_float_array(void *userdata, const char *key_str,
float **values, unsigned *out_num_values,
const float *default_values, unsigned num_default_values)
{
softfilter_get_array_setup()
softfilter_get_array_body(float)
}
rarch_softfilter_t *rarch_softfilter_new(const char *filter_path,
unsigned threads,
static int softfilter_get_int_array(void *userdata, const char *key_str,
int **values, unsigned *out_num_values,
const int *default_values, unsigned num_default_values)
{
softfilter_get_array_setup()
softfilter_get_array_body(int)
}
static int softfilter_get_string(void *userdata, const char *key_str,
char **output, const char *default_output)
{
softfilter_get_array_setup()
if (got)
{
*output = str;
return true;
}
else
{
*output = strdup(default_output);
return false;
}
}
static void softfilter_free(void *ptr)
{
free(ptr);
}
static const struct softfilter_config softfilter_config = {
softfilter_get_float,
softfilter_get_int,
softfilter_get_float_array,
softfilter_get_int_array,
softfilter_get_string,
softfilter_free,
};
static bool create_softfilter_graph(rarch_softfilter_t *filt,
enum retro_pixel_format in_pixel_format,
unsigned max_width, unsigned max_height)
unsigned max_width, unsigned max_height,
unsigned threads)
{
unsigned cpu_features, output_fmts, input_fmts, input_fmt;
(void)filter_path;
unsigned input_fmts, input_fmt, output_fmts;
char key[64];
struct softfilter_userdata userdata;
#if defined(HAVE_FILTERS_BUILTIN)
if (!g_settings.video.filter_idx)
return NULL;
#endif
snprintf(key, sizeof(key), "filter");
rarch_softfilter_t *filt = (rarch_softfilter_t*)calloc(1, sizeof(*filt));
if (!filt)
return NULL;
char name[64];
if (!config_get_array(filt->conf, key, name, sizeof(name)))
return false;
softfilter_get_implementation_t cb = NULL;
#if defined(HAVE_FILTERS_BUILTIN)
cb = (softfilter_get_implementation_t)softfilter_get_implementation_from_idx(g_settings.video.filter_idx);
#elif defined(HAVE_DYLIB)
RARCH_LOG("Loading softfilter from \"%s\"\n", filter_path);
filt->lib = dylib_load(filter_path);
if (!filt->lib)
goto error;
cb = (softfilter_get_implementation_t)dylib_proc(filt->lib, "softfilter_get_implementation");
#endif
if (!cb)
{
RARCH_ERR("Couldn't find softfilter symbol.\n");
goto error;
}
cpu_features = rarch_get_cpu_features();
filt->impl = cb(cpu_features);
filt->impl = softfilter_find_implementation(filt, name);
if (!filt->impl)
goto error;
return false;
RARCH_LOG("Loaded softfilter \"%s\".\n", filt->impl->ident);
if (filt->impl->api_version != SOFTFILTER_API_VERSION)
{
RARCH_ERR("Softfilter ABI mismatch.\n");
goto error;
}
userdata.conf = filt->conf;
userdata.prefix[0] = key; // Index-specific configs take priority over ident-specific.
userdata.prefix[1] = filt->impl->short_ident;
// Simple assumptions.
filt->pix_fmt = in_pixel_format;
@ -202,13 +257,13 @@ rarch_softfilter_t *rarch_softfilter_new(const char *filter_path,
input_fmt = SOFTFILTER_FMT_RGB565;
break;
default:
goto error;
return false;
}
if (!(input_fmt & input_fmts))
{
RARCH_ERR("Softfilter does not support input format.\n");
goto error;
return false;
}
output_fmts = filt->impl->query_output_formats(input_fmt);
@ -221,25 +276,26 @@ rarch_softfilter_t *rarch_softfilter_new(const char *filter_path,
else
{
RARCH_ERR("Did not find suitable output format for softfilter.\n");
goto error;
return false;
}
filt->max_width = max_width;
filt->max_height = max_height;
filt->impl_data = filt->impl->create(NULL, input_fmt, input_fmt, max_width, max_height,
threads != RARCH_SOFTFILTER_THREADS_AUTO ? threads : rarch_get_cpu_cores(), cpu_features);
filt->impl_data = filt->impl->create(&softfilter_config, input_fmt, input_fmt, max_width, max_height,
threads != RARCH_SOFTFILTER_THREADS_AUTO ? threads : rarch_get_cpu_cores(), rarch_get_cpu_features(),
&userdata);
if (!filt->impl_data)
{
RARCH_ERR("Failed to create softfilter state.\n");
goto error;
return false;
}
threads = filt->impl->query_num_threads(filt->impl_data);
if (!threads)
{
RARCH_ERR("Invalid number of threads.\n");
goto error;
return false;
}
RARCH_LOG("Using %u threads for softfilter.\n", threads);
@ -248,13 +304,13 @@ rarch_softfilter_t *rarch_softfilter_new(const char *filter_path,
if (!filt->packets)
{
RARCH_ERR("Failed to allocate softfilter packets.\n");
goto error;
return false;
}
#ifdef HAVE_THREADS
filt->thread_data = (struct filter_thread_data*)calloc(threads, sizeof(*filt->thread_data));
if (!filt->thread_data)
goto error;
return false;
filt->threads = threads;
unsigned i;
@ -265,19 +321,165 @@ rarch_softfilter_t *rarch_softfilter_new(const char *filter_path,
filt->thread_data[i].lock = slock_new();
if (!filt->thread_data[i].lock)
goto error;
return false;
filt->thread_data[i].cond = scond_new();
if (!filt->thread_data[i].cond)
goto error;
return false;
filt->thread_data[i].thread = sthread_create(filter_thread_loop, &filt->thread_data[i]);
if (!filt->thread_data[i].thread)
goto error;
return false;
}
#endif
return true;
}
#ifdef HAVE_FILTERS_BUILTIN
extern const struct softfilter_implementation *blargg_ntsc_snes_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *lq2x_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *phosphor2x_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *twoxbr_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *epx_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *twoxsai_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *supereagle_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *supertwoxsai_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *twoxbr_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *darken_get_implementation(softfilter_simd_mask_t simd);
extern const struct softfilter_implementation *scale2x_get_implementation(softfilter_simd_mask_t simd);
static const softfilter_get_implementation_t soft_plugs_builtin[] = {
blargg_ntsc_snes_get_implementation,
lq2x_get_implementation,
phosphor2x_get_implementation,
twoxbr_get_implementation,
darken_get_implementation,
twoxsai_get_implementation,
supertwoxsai_get_implementation,
supereagle_get_implementation,
epx_get_implementation,
scale2x_get_implementation,
};
static bool append_softfilter_plugs(rarch_softfilter_t *filt)
{
unsigned i;
softfilter_simd_mask_t mask = rarch_get_cpu_features();
filt->plugs = (struct rarch_soft_plug*)calloc(ARRAY_SIZE(soft_plugs_builtin), sizeof(*filt->plugs));
if (!filt->plugs)
return false;
filt->num_plugs = ARRAY_SIZE(soft_plugs_builtin);
for (i = 0; i < ARRAY_SIZE(soft_plugs_builtin); i++)
{
filt->plugs[i].impl = soft_plugs_builtin[i](mask);
if (!filt->plugs[i].impl)
return false;
}
return true;
}
#else
static bool append_softfilter_plugs(rarch_softfilter_t *filt, struct string_list *list)
{
unsigned i;
softfilter_simd_mask_t mask = rarch_get_cpu_features();
for (i = 0; i < list->size; i++)
{
dylib_t lib = dylib_load(list->elems[i].data);
if (!lib)
continue;
softfilter_get_implementation_t cb = (softfilter_get_implementation_t)dylib_proc(lib, "softfilter_get_implementation");
if (!cb)
{
dylib_close(lib);
continue;
}
const struct softfilter_implementation *impl = cb(mask);
if (!impl)
{
dylib_close(lib);
continue;
}
if (impl->api_version != SOFTFILTER_API_VERSION)
{
dylib_close(lib);
continue;
}
struct rarch_soft_plug *new_plugs = (struct rarch_soft_plug*)realloc(filt->plugs, sizeof(*filt->plugs) * (filt->num_plugs + 1));
if (!new_plugs)
{
dylib_close(lib);
return false;
}
RARCH_LOG("[SoftFilter]: Found plug: %s (%s).\n", impl->ident, impl->short_ident);
filt->plugs = new_plugs;
filt->plugs[filt->num_plugs].lib = lib;
filt->plugs[filt->num_plugs].impl = impl;
filt->num_plugs++;
}
return true;
}
#endif
rarch_softfilter_t *rarch_softfilter_new(const char *filter_config,
unsigned threads,
enum retro_pixel_format in_pixel_format,
unsigned max_width, unsigned max_height)
{
#if !defined(HAVE_FILTERS_BUILTIN) && defined(HAVE_DYLIB)
char basedir[PATH_MAX];
#endif
unsigned cpu_features;
struct string_list *plugs = NULL;
rarch_softfilter_t *filt = (rarch_softfilter_t*)calloc(1, sizeof(*filt));
if (!filt)
return NULL;
filt->conf = config_file_new(filter_config);
if (!filt->conf)
{
RARCH_ERR("[SoftFilter]: Did not find config: %s\n", filter_config);
goto error;
}
#if defined(HAVE_FILTERS_BUILTIN)
if (!append_softfilter_plugs(filt))
goto error;
#elif defined(HAVE_DYLIB)
fill_pathname_basedir(basedir, filter_config, sizeof(basedir));
plugs = dir_list_new(basedir, EXT_EXECUTABLES, false);
if (!plugs)
goto error;
if (!append_softfilter_plugs(filt, plugs))
goto error;
string_list_free(plugs);
plugs = NULL;
#endif
if (!create_softfilter_graph(filt, in_pixel_format,
max_width, max_height, threads))
goto error;
return filt;
error:
string_list_free(plugs);
rarch_softfilter_free(filt);
return NULL;
}
@ -285,18 +487,24 @@ error:
void rarch_softfilter_free(rarch_softfilter_t *filt)
{
unsigned i;
i = 0;
(void)i;
if (!filt)
return;
free(filt->packets);
if (filt->impl && filt->impl_data)
filt->impl->destroy(filt->impl_data);
#if !defined(HAVE_FILTERS_BUILTIN) && defined(HAVE_DYLIB)
if (filt->lib)
dylib_close(filt->lib);
#ifdef HAVE_DYLIB
for (i = 0; i < filt->num_plugs; i++)
{
if (filt->plugs[i].lib)
dylib_close(filt->plugs[i].lib);
}
free(filt->plugs);
#endif
#ifdef HAVE_THREADS
for (i = 0; i < filt->threads; i++)
{

1
gfx/filters/2xBR.filt Normal file
View File

@ -0,0 +1 @@
filter = 2xbr

1
gfx/filters/2xSaI.filt Normal file
View File

@ -0,0 +1 @@
filter = 2xsai

View File

@ -37,6 +37,7 @@
#include "softfilter.h"
#include <stdlib.h>
#include <string.h>
#ifdef RARCH_INTERNAL
#define softfilter_get_implementation twoxbr_get_implementation
@ -223,10 +224,11 @@ static void SetupFormat(void * data)
static void *twoxbr_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)
unsigned threads, softfilter_simd_mask_t simd, void *userdata)
{
(void)simd;
(void)config;
(void)userdata;
struct filter_data *filt = (struct filter_data*)calloc(1, sizeof(*filt));
if (!filt)
@ -720,8 +722,9 @@ static const struct softfilter_implementation twoxbr_generic = {
twoxbr_generic_threads,
twoxbr_generic_output,
twoxbr_generic_packets,
"2xBR",
SOFTFILTER_API_VERSION,
"2xBR",
"2xbr",
};
const struct softfilter_implementation *softfilter_get_implementation(softfilter_simd_mask_t simd)

View File

@ -18,6 +18,7 @@
#include "softfilter.h"
#include <stdlib.h>
#include <string.h>
#ifdef RARCH_INTERNAL
#define softfilter_get_implementation twoxsai_get_implementation
@ -66,10 +67,11 @@ static unsigned twoxsai_generic_threads(void *data)
static void *twoxsai_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)
unsigned threads, softfilter_simd_mask_t simd, void *userdata)
{
(void)simd;
(void)config;
(void)userdata;
struct filter_data *filt = (struct filter_data*)calloc(1, sizeof(*filt));
if (!filt)
@ -347,8 +349,9 @@ static const struct softfilter_implementation twoxsai_generic = {
twoxsai_generic_threads,
twoxsai_generic_output,
twoxsai_generic_packets,
"2xSaI",
SOFTFILTER_API_VERSION,
"2xSaI",
"2xsai",
};
const struct softfilter_implementation *softfilter_get_implementation(softfilter_simd_mask_t simd)

View File

@ -0,0 +1,3 @@
filter = blargg_ntsc_snes
tvtype = "composite"

View File

@ -0,0 +1,2 @@
filter = blargg_ntsc_snes
tvtype = "rf"

View File

@ -0,0 +1,3 @@
filter = blargg_ntsc_snes
tvtype = "rgb"

View File

@ -0,0 +1,2 @@
filter = blargg_ntsc_snes
tvtype = "svideo"

1
gfx/filters/Darken.filt Normal file
View File

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

1
gfx/filters/EPX.filt Normal file
View File

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

1
gfx/filters/LQ2x.filt Normal file
View File

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

View File

@ -68,7 +68,7 @@ ASMFLAGS := -INEON/asm
asflags += -mfpu=neon
endif
objects += blargg_ntsc_snes_composite.$(DYLIB) blargg_ntsc_snes_rf.$(DYLIB) blargg_ntsc_snes_svideo.$(DYLIB) blargg_ntsc_snes_rgb.$(DYLIB) phosphor2x.$(DYLIB) epx.$(DYLIB) lq2x.$(DYLIB) 2xsai.$(DYLIB) super2xsai.$(DYLIB) supereagle.$(DYLIB) 2xbr.$(DYLIB) darken.$(DYLIB) scale2x.$(DYLIB)
objects += blargg_ntsc_snes.$(DYLIB) phosphor2x.$(DYLIB) epx.$(DYLIB) lq2x.$(DYLIB) 2xsai.$(DYLIB) super2xsai.$(DYLIB) supereagle.$(DYLIB) 2xbr.$(DYLIB) darken.$(DYLIB) scale2x.$(DYLIB)
all: build;

View File

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

1
gfx/filters/Scale2x.filt Normal file
View File

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

View File

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

View File

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

View File

@ -15,15 +15,17 @@
*/
#include "softfilter.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "boolean.h"
#include "snes_ntsc/snes_ntsc.h"
#include "snes_ntsc/snes_ntsc.c"
#ifdef RARCH_INTERNAL
#define softfilter_get_implementation blargg_ntsc_snes_composite_get_implementation
#define softfilter_thread_data blargg_ntsc_snes_composite_softfilter_thread_data
#define filter_data blargg_ntsc_snes_composite_filter_data
#define softfilter_get_implementation blargg_ntsc_snes_get_implementation
#define softfilter_thread_data blargg_ntsc_snes_softfilter_thread_data
#define filter_data blargg_ntsc_snes_filter_data
#endif
struct softfilter_thread_data
@ -50,43 +52,76 @@ struct filter_data
};
static unsigned blargg_ntsc_snes_composite_generic_input_fmts(void)
static unsigned blargg_ntsc_snes_generic_input_fmts(void)
{
return SOFTFILTER_FMT_RGB565;
}
static unsigned blargg_ntsc_snes_composite_generic_output_fmts(unsigned input_fmts)
static unsigned blargg_ntsc_snes_generic_output_fmts(unsigned input_fmts)
{
return input_fmts;
}
static unsigned blargg_ntsc_snes_composite_generic_threads(void *data)
static unsigned blargg_ntsc_snes_generic_threads(void *data)
{
struct filter_data *filt = (struct filter_data*)data;
return filt->threads;
}
static void blargg_ntsc_snes_composite_initialize(void *data)
static void blargg_ntsc_snes_initialize(void *data,
const struct softfilter_config *config,
void *userdata)
{
char *tvtype = NULL;
snes_ntsc_setup_t setup;
struct filter_data *filt = (struct filter_data*)data;
filt->ntsc = (snes_ntsc_t*)calloc(1, sizeof(*filt->ntsc));
setup = snes_ntsc_composite;
setup.merge_fields = 1;
if (config->get_string(userdata, "tvtype", &tvtype, "composite"))
{
if (!strcmp(tvtype, "composite"))
{
setup = snes_ntsc_composite;
setup.merge_fields = 1;
}
else if (!strcmp(tvtype, "rf"))
{
setup = snes_ntsc_composite;
setup.merge_fields = 0;
}
else if (!strcmp(tvtype, "rgb"))
{
setup = snes_ntsc_rgb;
setup.merge_fields = 1;
}
else if (!strcmp(tvtype, "svideo"))
{
setup = snes_ntsc_svideo;
setup.merge_fields = 1;
}
}
else
{
setup = snes_ntsc_composite;
setup.merge_fields = 1;
}
config->free(tvtype);
tvtype = NULL;
snes_ntsc_init(filt->ntsc, &setup);
filt->burst = 0;
filt->burst_toggle = (setup.merge_fields ? 0 : 1);
}
static void *blargg_ntsc_snes_composite_generic_create(const struct softfilter_config *config,
static void *blargg_ntsc_snes_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)
unsigned threads, softfilter_simd_mask_t simd, void *userdata)
{
(void)simd;
(void)config;
struct filter_data *filt = (struct filter_data*)calloc(1, sizeof(*filt));
if (!filt)
@ -99,20 +134,21 @@ static void *blargg_ntsc_snes_composite_generic_create(const struct softfilter_c
free(filt);
return NULL;
}
blargg_ntsc_snes_composite_initialize(filt);
blargg_ntsc_snes_initialize(filt, config, userdata);
return filt;
}
static void blargg_ntsc_snes_composite_generic_output(void *data, unsigned *out_width, unsigned *out_height,
static void blargg_ntsc_snes_generic_output(void *data, unsigned *out_width, unsigned *out_height,
unsigned width, unsigned height)
{
*out_width = SNES_NTSC_OUT_WIDTH(width);
*out_height = height;
}
static void blargg_ntsc_snes_composite_generic_destroy(void *data)
static void blargg_ntsc_snes_generic_destroy(void *data)
{
struct filter_data *filt = (struct filter_data*)data;
@ -123,7 +159,7 @@ static void blargg_ntsc_snes_composite_generic_destroy(void *data)
free(filt);
}
static void blargg_ntsc_snes_composite_render_rgb565(void *data, int width, int height,
static void blargg_ntsc_snes_render_rgb565(void *data, int width, int height,
int first, int last,
uint16_t *input, int pitch, uint16_t *output, int outpitch)
{
@ -136,18 +172,18 @@ static void blargg_ntsc_snes_composite_render_rgb565(void *data, int width, int
filt->burst ^= filt->burst_toggle;
}
static void blargg_ntsc_snes_composite_rgb565(void *data, unsigned width, unsigned height,
static void blargg_ntsc_snes_rgb565(void *data, unsigned width, unsigned height,
int first, int last, uint16_t *src,
unsigned src_stride, uint16_t *dst, unsigned dst_stride)
{
blargg_ntsc_snes_composite_render_rgb565(data, width, height,
blargg_ntsc_snes_render_rgb565(data, width, height,
first, last,
src, src_stride,
dst, dst_stride);
}
static void blargg_ntsc_snes_composite_work_cb_rgb565(void *data, void *thread_data)
static void blargg_ntsc_snes_work_cb_rgb565(void *data, void *thread_data)
{
struct softfilter_thread_data *thr = (struct softfilter_thread_data*)thread_data;
uint16_t *input = (uint16_t*)thr->in_data;
@ -155,11 +191,11 @@ static void blargg_ntsc_snes_composite_work_cb_rgb565(void *data, void *thread_d
unsigned width = thr->width;
unsigned height = thr->height;
blargg_ntsc_snes_composite_rgb565(data, width, height,
blargg_ntsc_snes_rgb565(data, width, height,
thr->first, thr->last, input, thr->in_pitch / SOFTFILTER_BPP_RGB565, output, thr->out_pitch / SOFTFILTER_BPP_RGB565);
}
static void blargg_ntsc_snes_composite_generic_packets(void *data,
static void blargg_ntsc_snes_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)
@ -184,29 +220,30 @@ static void blargg_ntsc_snes_composite_generic_packets(void *data,
thr->last = y_end == height;
if (filt->in_fmt == SOFTFILTER_FMT_RGB565)
packets[i].work = blargg_ntsc_snes_composite_work_cb_rgb565;
packets[i].work = blargg_ntsc_snes_work_cb_rgb565;
packets[i].thread_data = thr;
}
}
static const struct softfilter_implementation blargg_ntsc_snes_composite_generic = {
blargg_ntsc_snes_composite_generic_input_fmts,
blargg_ntsc_snes_composite_generic_output_fmts,
static const struct softfilter_implementation blargg_ntsc_snes_generic = {
blargg_ntsc_snes_generic_input_fmts,
blargg_ntsc_snes_generic_output_fmts,
blargg_ntsc_snes_composite_generic_create,
blargg_ntsc_snes_composite_generic_destroy,
blargg_ntsc_snes_generic_create,
blargg_ntsc_snes_generic_destroy,
blargg_ntsc_snes_composite_generic_threads,
blargg_ntsc_snes_composite_generic_output,
blargg_ntsc_snes_composite_generic_packets,
"Blargg NTSC SNES Composite",
blargg_ntsc_snes_generic_threads,
blargg_ntsc_snes_generic_output,
blargg_ntsc_snes_generic_packets,
SOFTFILTER_API_VERSION,
"Blargg NTSC SNES",
"blargg_ntsc_snes",
};
const struct softfilter_implementation *softfilter_get_implementation(softfilter_simd_mask_t simd)
{
(void)simd;
return &blargg_ntsc_snes_composite_generic;
return &blargg_ntsc_snes_generic;
}
#ifdef RARCH_INTERNAL

View File

@ -1,214 +0,0 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2011-2014 - 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/>.
*/
#include "softfilter.h"
#include <stdlib.h>
#include "boolean.h"
#include "snes_ntsc/snes_ntsc.h"
#include "snes_ntsc/snes_ntsc.c"
#ifdef RARCH_INTERNAL
#define softfilter_get_implementation blargg_ntsc_snes_rf_get_implementation
#define softfilter_thread_data blargg_ntsc_snes_rf_softfilter_thread_data
#define filter_data blargg_ntsc_snes_rf_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;
struct snes_ntsc_t *ntsc;
int burst;
int burst_toggle;
};
static unsigned blargg_ntsc_snes_rf_generic_input_fmts(void)
{
return SOFTFILTER_FMT_RGB565;
}
static unsigned blargg_ntsc_snes_rf_generic_output_fmts(unsigned input_fmts)
{
return input_fmts;
}
static unsigned blargg_ntsc_snes_rf_generic_threads(void *data)
{
struct filter_data *filt = (struct filter_data*)data;
return filt->threads;
}
static void blargg_ntsc_snes_rf_initialize(void *data)
{
snes_ntsc_setup_t setup;
struct filter_data *filt = (struct filter_data*)data;
filt->ntsc = (snes_ntsc_t*)calloc(1, sizeof(*filt->ntsc));
setup = snes_ntsc_composite;
setup.merge_fields = 0;
snes_ntsc_init(filt->ntsc, &setup);
filt->burst = 0;
filt->burst_toggle = (setup.merge_fields ? 0 : 1);
}
static void *blargg_ntsc_snes_rf_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)simd;
(void)config;
struct filter_data *filt = (struct filter_data*)calloc(1, sizeof(*filt));
if (!filt)
return NULL;
filt->workers = (struct softfilter_thread_data*)calloc(threads, sizeof(struct softfilter_thread_data));
filt->threads = threads;
filt->in_fmt = in_fmt;
if (!filt->workers)
{
free(filt);
return NULL;
}
blargg_ntsc_snes_rf_initialize(filt);
return filt;
}
static void blargg_ntsc_snes_rf_generic_output(void *data, unsigned *out_width, unsigned *out_height,
unsigned width, unsigned height)
{
*out_width = SNES_NTSC_OUT_WIDTH(width);
*out_height = height;
}
static void blargg_ntsc_snes_rf_generic_destroy(void *data)
{
struct filter_data *filt = (struct filter_data*)data;
if(filt->ntsc)
free(filt->ntsc);
free(filt->workers);
free(filt);
}
static void blargg_ntsc_snes_rf_render_rgb565(void *data, int width, int height,
int first, int last,
uint16_t *input, int pitch, uint16_t *output, int outpitch)
{
struct filter_data *filt = (struct filter_data*)data;
if(width <= 256)
snes_ntsc_blit(filt->ntsc, input, pitch, filt->burst, width, height, output, outpitch * 2, first, last);
else
snes_ntsc_blit_hires(filt->ntsc, input, pitch, filt->burst, width, height, output, outpitch * 2, first, last);
filt->burst ^= filt->burst_toggle;
}
static void blargg_ntsc_snes_rf_rgb565(void *data, unsigned width, unsigned height,
int first, int last, uint16_t *src,
unsigned src_stride, uint16_t *dst, unsigned dst_stride)
{
blargg_ntsc_snes_rf_render_rgb565(data, width, height,
first, last,
src, src_stride,
dst, dst_stride);
}
static void blargg_ntsc_snes_rf_work_cb_rgb565(void *data, void *thread_data)
{
struct softfilter_thread_data *thr = (struct softfilter_thread_data*)thread_data;
uint16_t *input = (uint16_t*)thr->in_data;
uint16_t *output = (uint16_t*)thr->out_data;
unsigned width = thr->width;
unsigned height = thr->height;
blargg_ntsc_snes_rf_rgb565(data, width, height,
thr->first, thr->last, input, thr->in_pitch / SOFTFILTER_BPP_RGB565, output, thr->out_pitch / SOFTFILTER_BPP_RGB565);
}
static void blargg_ntsc_snes_rf_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)
{
struct filter_data *filt = (struct filter_data*)data;
unsigned i;
for (i = 0; i < filt->threads; i++)
{
struct softfilter_thread_data *thr = (struct softfilter_thread_data*)&filt->workers[i];
unsigned y_start = (height * i) / filt->threads;
unsigned y_end = (height * (i + 1)) / filt->threads;
thr->out_data = (uint8_t*)output + y_start * output_stride;
thr->in_data = (const uint8_t*)input + y_start * input_stride;
thr->out_pitch = output_stride;
thr->in_pitch = input_stride;
thr->width = width;
thr->height = y_end - y_start;
// Workers need to know if they can access pixels outside their given buffer.
thr->first = y_start;
thr->last = y_end == height;
if (filt->in_fmt == SOFTFILTER_FMT_RGB565)
packets[i].work = blargg_ntsc_snes_rf_work_cb_rgb565;
packets[i].thread_data = thr;
}
}
static const struct softfilter_implementation blargg_ntsc_snes_rf_generic = {
blargg_ntsc_snes_rf_generic_input_fmts,
blargg_ntsc_snes_rf_generic_output_fmts,
blargg_ntsc_snes_rf_generic_create,
blargg_ntsc_snes_rf_generic_destroy,
blargg_ntsc_snes_rf_generic_threads,
blargg_ntsc_snes_rf_generic_output,
blargg_ntsc_snes_rf_generic_packets,
"Blargg NTSC NES/SNES RF",
SOFTFILTER_API_VERSION,
};
const struct softfilter_implementation *softfilter_get_implementation(softfilter_simd_mask_t simd)
{
(void)simd;
return &blargg_ntsc_snes_rf_generic;
}
#ifdef RARCH_INTERNAL
#undef softfilter_get_implementation
#undef softfilter_thread_data
#undef filter_data
#endif

View File

@ -1,215 +0,0 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2011-2014 - 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/>.
*/
#include "softfilter.h"
#include <stdlib.h>
#include "boolean.h"
#include "snes_ntsc/snes_ntsc.h"
#include "snes_ntsc/snes_ntsc.c"
#ifdef RARCH_INTERNAL
#define softfilter_get_implementation blargg_ntsc_snes_rgb_get_implementation
#define softfilter_thread_data blargg_ntsc_snes_rgb_softfilter_thread_data
#define filter_data blargg_ntsc_snes_rgb_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;
struct snes_ntsc_t *ntsc;
int burst;
int burst_toggle;
};
static unsigned blargg_ntsc_snes_rgb_generic_input_fmts(void)
{
return SOFTFILTER_FMT_RGB565;
}
static unsigned blargg_ntsc_snes_rgb_generic_output_fmts(unsigned input_fmts)
{
return input_fmts;
}
static unsigned blargg_ntsc_snes_rgb_generic_threads(void *data)
{
struct filter_data *filt = (struct filter_data*)data;
return filt->threads;
}
static void blargg_ntsc_snes_rgb_initialize(void *data)
{
snes_ntsc_setup_t setup;
struct filter_data *filt = (struct filter_data*)data;
filt->ntsc = (snes_ntsc_t*)calloc(1, sizeof(*filt->ntsc));
setup = snes_ntsc_rgb;
setup.merge_fields = 1;
snes_ntsc_init(filt->ntsc, &setup);
filt->burst = 0;
filt->burst_toggle = (setup.merge_fields ? 0 : 1);
}
static void *blargg_ntsc_snes_rgb_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)simd;
(void)config;
struct filter_data *filt = (struct filter_data*)calloc(1, sizeof(*filt));
if (!filt)
return NULL;
filt->workers = (struct softfilter_thread_data*)calloc(threads, sizeof(struct softfilter_thread_data));
filt->threads = threads;
filt->in_fmt = in_fmt;
if (!filt->workers)
{
free(filt);
return NULL;
}
blargg_ntsc_snes_rgb_initialize(filt);
return filt;
}
static void blargg_ntsc_snes_rgb_generic_output(void *data, unsigned *out_width, unsigned *out_height,
unsigned width, unsigned height)
{
*out_width = SNES_NTSC_OUT_WIDTH(width);
*out_height = height;
}
static void blargg_ntsc_snes_rgb_generic_destroy(void *data)
{
struct filter_data *filt = (struct filter_data*)data;
if(filt->ntsc)
free(filt->ntsc);
free(filt->workers);
free(filt);
}
static void blargg_ntsc_snes_rgb_render_rgb565(void *data, int width, int height,
int first, int last,
uint16_t *input, int pitch, uint16_t *output, int outpitch)
{
struct filter_data *filt = (struct filter_data*)data;
if(width <= 256)
snes_ntsc_blit(filt->ntsc, input, pitch, filt->burst, width, height, output, outpitch * 2, first, last);
else
snes_ntsc_blit_hires(filt->ntsc, input, pitch, filt->burst, width, height, output, outpitch * 2, first, last);
filt->burst ^= filt->burst_toggle;
}
static void blargg_ntsc_snes_rgb_rgb565(void *data, unsigned width, unsigned height,
int first, int last, uint16_t *src,
unsigned src_stride, uint16_t *dst, unsigned dst_stride)
{
blargg_ntsc_snes_rgb_render_rgb565(data, width, height,
first, last,
src, src_stride,
dst, dst_stride);
}
static void blargg_ntsc_snes_rgb_work_cb_rgb565(void *data, void *thread_data)
{
struct softfilter_thread_data *thr = (struct softfilter_thread_data*)thread_data;
uint16_t *input = (uint16_t*)thr->in_data;
uint16_t *output = (uint16_t*)thr->out_data;
unsigned width = thr->width;
unsigned height = thr->height;
blargg_ntsc_snes_rgb_rgb565(data, width, height,
thr->first, thr->last, input, thr->in_pitch / SOFTFILTER_BPP_RGB565, output, thr->out_pitch / SOFTFILTER_BPP_RGB565);
}
static void blargg_ntsc_snes_rgb_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)
{
struct filter_data *filt = (struct filter_data*)data;
unsigned i;
for (i = 0; i < filt->threads; i++)
{
struct softfilter_thread_data *thr = (struct softfilter_thread_data*)&filt->workers[i];
unsigned y_start = (height * i) / filt->threads;
unsigned y_end = (height * (i + 1)) / filt->threads;
thr->out_data = (uint8_t*)output + y_start * output_stride;
thr->in_data = (const uint8_t*)input + y_start * input_stride;
thr->out_pitch = output_stride;
thr->in_pitch = input_stride;
thr->width = width;
thr->height = y_end - y_start;
// Workers need to know if they can access pixels outside their given buffer.
thr->first = y_start;
thr->last = y_end == height;
if (filt->in_fmt == SOFTFILTER_FMT_RGB565)
packets[i].work = blargg_ntsc_snes_rgb_work_cb_rgb565;
packets[i].thread_data = thr;
}
}
static const struct softfilter_implementation blargg_ntsc_snes_rgb_generic = {
blargg_ntsc_snes_rgb_generic_input_fmts,
blargg_ntsc_snes_rgb_generic_output_fmts,
blargg_ntsc_snes_rgb_generic_create,
blargg_ntsc_snes_rgb_generic_destroy,
blargg_ntsc_snes_rgb_generic_threads,
blargg_ntsc_snes_rgb_generic_output,
blargg_ntsc_snes_rgb_generic_packets,
"Blargg NTSC NES/SNES RGB",
SOFTFILTER_API_VERSION,
};
const struct softfilter_implementation *softfilter_get_implementation(softfilter_simd_mask_t simd)
{
(void)simd;
return &blargg_ntsc_snes_rgb_generic;
}
#ifdef RARCH_INTERNAL
#undef softfilter_get_implementation
#undef softfilter_thread_data
#undef filter_data
#endif

View File

@ -1,214 +0,0 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2011-2014 - 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/>.
*/
#include "softfilter.h"
#include <stdlib.h>
#include "boolean.h"
#include "snes_ntsc/snes_ntsc.h"
#include "snes_ntsc/snes_ntsc.c"
#ifdef RARCH_INTERNAL
#define softfilter_get_implementation blargg_ntsc_snes_svideo_get_implementation
#define softfilter_thread_data blargg_ntsc_snes_svideo_softfilter_thread_data
#define filter_data blargg_ntsc_snes_svideo_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;
struct snes_ntsc_t *ntsc;
int burst;
int burst_toggle;
};
static unsigned blargg_ntsc_snes_svideo_generic_input_fmts(void)
{
return SOFTFILTER_FMT_RGB565;
}
static unsigned blargg_ntsc_snes_svideo_generic_output_fmts(unsigned input_fmts)
{
return input_fmts;
}
static unsigned blargg_ntsc_snes_svideo_generic_threads(void *data)
{
struct filter_data *filt = (struct filter_data*)data;
return filt->threads;
}
static void blargg_ntsc_snes_svideo_initialize(void *data)
{
snes_ntsc_setup_t setup;
struct filter_data *filt = (struct filter_data*)data;
filt->ntsc = (snes_ntsc_t*)calloc(1, sizeof(*filt->ntsc));
setup = snes_ntsc_svideo;
setup.merge_fields = 1;
snes_ntsc_init(filt->ntsc, &setup);
filt->burst = 0;
filt->burst_toggle = (setup.merge_fields ? 0 : 1);
}
static void *blargg_ntsc_snes_svideo_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)simd;
(void)config;
struct filter_data *filt = (struct filter_data*)calloc(1, sizeof(*filt));
if (!filt)
return NULL;
filt->workers = (struct softfilter_thread_data*)calloc(threads, sizeof(struct softfilter_thread_data));
filt->threads = threads;
filt->in_fmt = in_fmt;
if (!filt->workers)
{
free(filt);
return NULL;
}
blargg_ntsc_snes_svideo_initialize(filt);
return filt;
}
static void blargg_ntsc_snes_svideo_generic_output(void *data, unsigned *out_width, unsigned *out_height,
unsigned width, unsigned height)
{
*out_width = SNES_NTSC_OUT_WIDTH(width);
*out_height = height;
}
static void blargg_ntsc_snes_svideo_generic_destroy(void *data)
{
struct filter_data *filt = (struct filter_data*)data;
if(filt->ntsc)
free(filt->ntsc);
free(filt->workers);
free(filt);
}
static void blargg_ntsc_snes_svideo_render_rgb565(void *data, int width, int height,
int first, int last,
uint16_t *input, int pitch, uint16_t *output, int outpitch)
{
struct filter_data *filt = (struct filter_data*)data;
if(width <= 256)
snes_ntsc_blit(filt->ntsc, input, pitch, filt->burst, width, height, output, outpitch * 2, first, last);
else
snes_ntsc_blit_hires(filt->ntsc, input, pitch, filt->burst, width, height, output, outpitch * 2, first, last);
filt->burst ^= filt->burst_toggle;
}
static void blargg_ntsc_snes_svideo_rgb565(void *data, unsigned width, unsigned height,
int first, int last, uint16_t *src,
unsigned src_stride, uint16_t *dst, unsigned dst_stride)
{
blargg_ntsc_snes_svideo_render_rgb565(data, width, height,
first, last,
src, src_stride,
dst, dst_stride);
}
static void blargg_ntsc_snes_svideo_work_cb_rgb565(void *data, void *thread_data)
{
struct softfilter_thread_data *thr = (struct softfilter_thread_data*)thread_data;
uint16_t *input = (uint16_t*)thr->in_data;
uint16_t *output = (uint16_t*)thr->out_data;
unsigned width = thr->width;
unsigned height = thr->height;
blargg_ntsc_snes_svideo_rgb565(data, width, height,
thr->first, thr->last, input, thr->in_pitch / SOFTFILTER_BPP_RGB565, output, thr->out_pitch / SOFTFILTER_BPP_RGB565);
}
static void blargg_ntsc_snes_svideo_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)
{
struct filter_data *filt = (struct filter_data*)data;
unsigned i;
for (i = 0; i < filt->threads; i++)
{
struct softfilter_thread_data *thr = (struct softfilter_thread_data*)&filt->workers[i];
unsigned y_start = (height * i) / filt->threads;
unsigned y_end = (height * (i + 1)) / filt->threads;
thr->out_data = (uint8_t*)output + y_start * output_stride;
thr->in_data = (const uint8_t*)input + y_start * input_stride;
thr->out_pitch = output_stride;
thr->in_pitch = input_stride;
thr->width = width;
thr->height = y_end - y_start;
// Workers need to know if they can access pixels outside their given buffer.
thr->first = y_start;
thr->last = y_end == height;
if (filt->in_fmt == SOFTFILTER_FMT_RGB565)
packets[i].work = blargg_ntsc_snes_svideo_work_cb_rgb565;
packets[i].thread_data = thr;
}
}
static const struct softfilter_implementation blargg_ntsc_snes_svideo_generic = {
blargg_ntsc_snes_svideo_generic_input_fmts,
blargg_ntsc_snes_svideo_generic_output_fmts,
blargg_ntsc_snes_svideo_generic_create,
blargg_ntsc_snes_svideo_generic_destroy,
blargg_ntsc_snes_svideo_generic_threads,
blargg_ntsc_snes_svideo_generic_output,
blargg_ntsc_snes_svideo_generic_packets,
"Blargg NTSC NES/SNES S-Video",
SOFTFILTER_API_VERSION,
};
const struct softfilter_implementation *softfilter_get_implementation(softfilter_simd_mask_t simd)
{
(void)simd;
return &blargg_ntsc_snes_svideo_generic;
}
#ifdef RARCH_INTERNAL
#undef softfilter_get_implementation
#undef softfilter_thread_data
#undef filter_data
#endif

View File

@ -66,10 +66,11 @@ static unsigned darken_threads(void *data)
static void *darken_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)
unsigned threads, softfilter_simd_mask_t simd, void *userdata)
{
(void)simd;
(void)config;
(void)userdata;
struct filter_data *filt = (struct filter_data*)calloc(1, sizeof(*filt));
if (!filt)
@ -164,8 +165,9 @@ static const struct softfilter_implementation darken = {
darken_threads,
darken_output,
darken_packets,
"Darken",
SOFTFILTER_API_VERSION,
"Darken",
"darken",
};
const struct softfilter_implementation *softfilter_get_implementation(softfilter_simd_mask_t simd)

View File

@ -66,10 +66,11 @@ static unsigned epx_generic_threads(void *data)
static void *epx_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)
unsigned threads, softfilter_simd_mask_t simd, void *userdata)
{
(void)simd;
(void)config;
(void)userdata;
struct filter_data *filt = (struct filter_data*)calloc(1, sizeof(*filt));
if (!filt)
@ -416,8 +417,9 @@ static const struct softfilter_implementation epx_generic = {
epx_generic_threads,
epx_generic_output,
epx_generic_packets,
"EPX",
SOFTFILTER_API_VERSION,
"EPX",
"epx",
};
const struct softfilter_implementation *softfilter_get_implementation(softfilter_simd_mask_t simd)

View File

@ -66,10 +66,11 @@ static unsigned lq2x_generic_threads(void *data)
static void *lq2x_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)
unsigned threads, softfilter_simd_mask_t simd, void *userdata)
{
(void)simd;
(void)config;
(void)userdata;
struct filter_data *filt = (struct filter_data*)calloc(1, sizeof(*filt));
if (!filt)
@ -261,8 +262,9 @@ static const struct softfilter_implementation lq2x_generic = {
lq2x_generic_threads,
lq2x_generic_output,
lq2x_generic_packets,
"LQ2x",
SOFTFILTER_API_VERSION,
"LQ2x",
"lq2x",
};
const struct softfilter_implementation *softfilter_get_implementation(softfilter_simd_mask_t simd)

View File

@ -219,7 +219,7 @@ static unsigned phosphor2x_generic_threads(void *data)
static void *phosphor2x_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)
unsigned threads, softfilter_simd_mask_t simd, void *userdata)
{
unsigned i;
struct filter_data *filt = (struct filter_data*)calloc(1, sizeof(*filt));
@ -229,6 +229,7 @@ static void *phosphor2x_generic_create(const struct softfilter_config *config,
(void)max_width;
(void)max_height;
(void)config;
(void)userdata;
if (!filt)
return NULL;
@ -420,8 +421,9 @@ static const struct softfilter_implementation phosphor2x_generic = {
phosphor2x_generic_threads,
phosphor2x_generic_output,
phosphor2x_generic_packets,
"Phosphor2x",
SOFTFILTER_API_VERSION,
"Phosphor2x",
"phosphor2x",
};
const struct softfilter_implementation *softfilter_get_implementation(softfilter_simd_mask_t simd)

View File

@ -125,10 +125,11 @@ static unsigned scale2x_generic_threads(void *data)
static void *scale2x_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)
unsigned threads, softfilter_simd_mask_t simd, void *userdata)
{
(void)simd;
(void)config;
(void)userdata;
struct filter_data *filt = (struct filter_data*)calloc(1, sizeof(*filt));
if (!filt)
@ -224,8 +225,9 @@ static const struct softfilter_implementation scale2x_generic = {
scale2x_generic_threads,
scale2x_generic_output,
scale2x_generic_packets,
"Scale2x",
SOFTFILTER_API_VERSION,
"Scale2x",
"scale2x",
};
const struct softfilter_implementation *softfilter_get_implementation(softfilter_simd_mask_t simd)

View File

@ -111,7 +111,7 @@ struct softfilter_work_packet
// Input sizes can very per call to softfilter_process_t, but they will never be larger than the maximum.
typedef void *(*softfilter_create_t)(const struct softfilter_config *config, unsigned in_fmt, unsigned out_fmt,
unsigned max_width, unsigned max_height,
unsigned threads, softfilter_simd_mask_t simd);
unsigned threads, softfilter_simd_mask_t simd, void *userdata);
typedef void (*softfilter_destroy_t)(void *data);
// Given an input size, query the output size of the filter.
@ -145,8 +145,9 @@ struct softfilter_implementation
softfilter_query_output_size_t query_output_size;
softfilter_get_work_packets_t get_work_packets;
const char *ident; // Human readable identifier of implementation.
unsigned api_version; // Must be SOFTFILTER_API_VERSION
const char *ident; // Human readable identifier of implementation.
const char *short_ident; // Computer-friendly short version of ident. Lower case, no spaces and special characters, etc.
};
#ifdef __cplusplus

View File

@ -66,10 +66,11 @@ static unsigned supertwoxsai_generic_threads(void *data)
static void *supertwoxsai_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)
unsigned threads, softfilter_simd_mask_t simd, void *userdata)
{
(void)simd;
(void)config;
(void)userdata;
struct filter_data *filt = (struct filter_data*)calloc(1, sizeof(*filt));
if (!filt)
@ -319,8 +320,9 @@ static const struct softfilter_implementation supertwoxsai_generic = {
supertwoxsai_generic_threads,
supertwoxsai_generic_output,
supertwoxsai_generic_packets,
"Super2xSaI",
SOFTFILTER_API_VERSION,
"Super2xSaI",
"super2xsai",
};
const struct softfilter_implementation *softfilter_get_implementation(softfilter_simd_mask_t simd)

View File

@ -66,10 +66,11 @@ static unsigned supereagle_generic_threads(void *data)
static void *supereagle_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)
unsigned threads, softfilter_simd_mask_t simd, void *userdata)
{
(void)simd;
(void)config;
(void)userdata;
struct filter_data *filt = (struct filter_data*)calloc(1, sizeof(*filt));
if (!filt)
@ -324,8 +325,9 @@ static const struct softfilter_implementation supereagle_generic = {
supereagle_generic_threads,
supereagle_generic_output,
supereagle_generic_packets,
"SuperEagle",
SOFTFILTER_API_VERSION,
"SuperEagle",
"supereagle",
};
const struct softfilter_implementation *softfilter_get_implementation(softfilter_simd_mask_t simd)

View File

@ -433,8 +433,8 @@ void config_set_defaults(void)
*g_settings.video.shader_path = '\0';
*g_settings.video.shader_dir = '\0';
*g_settings.video.filter_dir = '\0';
*g_settings.video.filter_path = '\0';
*g_settings.audio.filter_dir = '\0';
*g_settings.video.softfilter_plugin = '\0';
*g_settings.audio.dsp_plugin = '\0';
#ifdef HAVE_MENU
*g_settings.menu_content_directory = '\0';
@ -836,10 +836,6 @@ bool config_load_file(const char *path, bool set_defaults)
CONFIG_GET_FLOAT(video.msg_pos_y, "video_message_pos_y");
CONFIG_GET_INT(video.rotation, "video_rotation");
#if defined(HAVE_FILTERS_BUILTIN)
CONFIG_GET_INT(video.filter_idx, "filter_index");
#endif
#ifdef RARCH_CONSOLE
/* TODO - will be refactored later to make it more clean - it's more
* important that it works for consoles right now */
@ -907,10 +903,6 @@ bool config_load_file(const char *path, bool set_defaults)
CONFIG_GET_BOOL(video.gpu_record, "video_gpu_record");
CONFIG_GET_BOOL(video.gpu_screenshot, "video_gpu_screenshot");
#ifdef HAVE_DYLIB
CONFIG_GET_PATH(video.filter_path, "video_filter");
#endif
CONFIG_GET_PATH(video.shader_dir, "video_shader_dir");
if (!strcmp(g_settings.video.shader_dir, "default"))
*g_settings.video.shader_dir = '\0';
@ -964,6 +956,7 @@ bool config_load_file(const char *path, bool set_defaults)
CONFIG_GET_STRING(menu.driver, "menu_driver");
CONFIG_GET_STRING(video.gl_context, "video_gl_context");
CONFIG_GET_STRING(audio.driver, "audio_driver");
CONFIG_GET_PATH(video.softfilter_plugin, "video_filter");
CONFIG_GET_PATH(audio.dsp_plugin, "audio_dsp_plugin");
CONFIG_GET_STRING(input.driver, "input_driver");
CONFIG_GET_STRING(input.joypad_driver, "input_joypad_driver");
@ -1327,9 +1320,6 @@ bool config_save_file(const char *path)
config_set_path(conf, "libretro_info_path", g_settings.libretro_info_path);
config_set_path(conf, "cheat_database_path", g_settings.cheat_database);
config_set_bool(conf, "rewind_enable", g_settings.rewind_enable);
#ifdef HAVE_FILTERS_BUILTIN
config_set_int(conf, "filter_index", g_settings.video.filter_idx);
#endif
config_set_int(conf, "audio_latency", g_settings.audio.latency);
config_set_bool(conf, "audio_sync", g_settings.audio.sync);
config_set_int(conf, "audio_block_frames", g_settings.audio.block_frames);
@ -1367,6 +1357,7 @@ bool config_save_file(const char *path)
config_set_path(conf, "screenshot_directory", *g_settings.screenshot_directory ? g_settings.screenshot_directory : "default");
config_set_int(conf, "aspect_ratio_index", g_settings.video.aspect_ratio_idx);
config_set_string(conf, "audio_device", g_settings.audio.device);
config_set_string(conf, "video_filter", g_settings.video.softfilter_plugin);
config_set_string(conf, "audio_dsp_plugin", g_settings.audio.dsp_plugin);
config_set_string(conf, "camera_device", g_settings.camera.device);
config_set_bool(conf, "camera_allow", g_settings.camera.allow);
@ -1387,7 +1378,6 @@ bool config_save_file(const char *path)
config_set_path(conf, "savefile_directory", *g_extern.savefile_dir ? g_extern.savefile_dir : "default");
config_set_path(conf, "savestate_directory", *g_extern.savestate_dir ? g_extern.savestate_dir : "default");
config_set_path(conf, "video_shader_dir", *g_settings.video.shader_dir ? g_settings.video.shader_dir : "default");
config_set_path(conf, "video_filter", g_settings.video.filter_path);
config_set_path(conf, "video_filter_dir", *g_settings.video.filter_dir ? g_settings.video.filter_dir : "default");
config_set_path(conf, "audio_filter_dir", *g_settings.audio.filter_dir ? g_settings.audio.filter_dir : "default");

View File

@ -1179,7 +1179,7 @@ static void general_read_handler(const void *data)
else if (!strcmp(setting->name, "video_aspect_ratio_auto"))
*setting->value.boolean = g_settings.video.aspect_ratio_auto;
else if (!strcmp(setting->name, "video_filter"))
strlcpy(setting->value.string, g_settings.video.filter_path, setting->size);
strlcpy(setting->value.string, g_settings.video.softfilter_plugin, setting->size);
else if (!strcmp(setting->name, "camera_allow"))
*setting->value.boolean = g_settings.camera.allow;
else if (!strcmp(setting->name, "location_allow"))
@ -1324,9 +1324,7 @@ static void general_write_handler(const void *data)
g_settings.audio.latency = *setting->value.unsigned_integer;
else if (!strcmp(setting->name, "audio_dsp_plugin"))
{
#ifdef HAVE_DYLIB
strlcpy(g_settings.audio.dsp_plugin, setting->value.string, sizeof(g_settings.audio.dsp_plugin));
#endif
rarch_cmd = RARCH_CMD_DSP_FILTER_INIT;
}
else if (!strcmp(setting->name, "state_slot"))
@ -1507,7 +1505,7 @@ static void general_write_handler(const void *data)
g_settings.video.aspect_ratio_auto = *setting->value.boolean;
else if (!strcmp(setting->name, "video_filter"))
{
strlcpy(g_settings.video.filter_path, setting->value.string, sizeof(g_settings.video.filter_path));
strlcpy(g_settings.video.softfilter_plugin, setting->value.string, sizeof(g_settings.video.softfilter_plugin));
rarch_cmd = RARCH_CMD_REINIT;
}
else if (!strcmp(setting->name, "video_filter_flicker"))
@ -1727,7 +1725,7 @@ rarch_setting_t* setting_data_get_list(void)
CONFIG_BOOL(g_settings.video.allow_rotate, "video_allow_rotate", "Allow rotation", allow_rotate, GROUP_NAME, SUBGROUP_NAME, general_write_handler, general_read_handler)
CONFIG_BOOL(g_settings.video.crop_overscan, "video_crop_overscan", "Crop Overscan (reload)", crop_overscan, GROUP_NAME, SUBGROUP_NAME, general_write_handler, general_read_handler)
#ifndef HAVE_FILTERS_BUILTIN
CONFIG_PATH(g_settings.video.filter_path, "video_filter", "Software filter", "", GROUP_NAME, SUBGROUP_NAME, general_write_handler, general_read_handler) WITH_FLAGS(SD_FLAG_ALLOW_EMPTY)
CONFIG_PATH(g_settings.video.softfilter_plugin, "video_filter", "Software filter", "", GROUP_NAME, SUBGROUP_NAME, general_write_handler, general_read_handler) WITH_FLAGS(SD_FLAG_ALLOW_EMPTY)
#endif
#ifdef _XBOX1
CONFIG_UINT(g_settings.video.swap_interval, "video_filter_flicker", "Flicker filter", 0, GROUP_NAME, SUBGROUP_NAME, general_write_handler, general_read_handler) WITH_RANGE(0, 5, 1, true, true)