Add stuff to detect filters.

This commit is contained in:
Themaister 2010-12-30 01:33:40 +01:00
parent 423fe969d3
commit 75d8781854
8 changed files with 189 additions and 150 deletions

View File

@ -50,6 +50,7 @@ ifeq ($(BUILD_FILTER), 1)
OBJ += hqflt/bleed.o
OBJ += hqflt/ntsc.o
OBJ += hqflt/snes_ntsc/snes_ntsc.o
DEFINES += -DHAVE_FILTER
endif
CFLAGS = -Wall -O0 -g -std=gnu99 -Wno-unused-variable -I. $(DEFINES)

View File

@ -39,7 +39,6 @@
#define AUDIO_AL 5
////////////////////////
// Chooses which video and audio subsystem to use. Remember to update config.mk if you change these.
#define VIDEO_DEFAULT_DRIVER VIDEO_GL
#define AUDIO_DEFAULT_DRIVER AUDIO_ALSA
@ -63,26 +62,24 @@ static const bool vsync = true;
// Smooths picture
static const bool video_smooth = true;
// Path to custom Cg shader. If using custom shaders, it is recommended to disable video_smooth.
#ifdef HAVE_CG
#define DEFAULT_CG_SHADER "hqflt/cg/quad.cg"
#endif
// On resize and fullscreen, rendering area will stay 4:3
static const bool force_aspect = true;
/////////// Video filters (CPU based)
#define FILTER_NONE 0
#ifdef HAVE_FILTER
#define FILTER_HQ2X 1
#define FILTER_HQ4X 2
#define FILTER_GRAYSCALE 3
#define FILTER_BLEED 4
#define FILTER_NTSC 5
#define FILTER_HQ2X_STR "hq2x"
#define FILTER_HQ4X_STR "hq4x"
#define FILTER_GRAYSCALE_STR "grayscale"
#define FILTER_BLEED_STR "bleed"
#define FILTER_NTSC_STR "ntsc"
#endif
////////////////////////
// If you change this to something other than FILTER_NONE, make sure that you build the filter module in config.mk.
#define VIDEO_FILTER FILTER_NONE
////////////////
// Audio

View File

@ -133,29 +133,25 @@ void uninit_audio(void)
void init_video_input(void)
{
int scale;
int scale = 2;
find_video_driver();
// We multiply scales with 2 to allow for hi-res games.
#if 0
#if VIDEO_FILTER == FILTER_NONE
scale = 2;
#elif VIDEO_FILTER == FILTER_HQ2X
scale = 4;
#elif VIDEO_FILTER == FILTER_HQ4X
scale = 8;
#elif VIDEO_FILTER == FILTER_NTSC
scale = 8;
#elif VIDEO_FILTER == FILTER_GRAYSCALE
scale = 2;
#elif VIDEO_FILTER == FILTER_BLEED
scale = 2;
#else
scale = 2;
#if HAVE_FILTER
switch (g_settings.video.filter)
{
case FILTER_HQ2X:
scale = 4;
break;
case FILTER_HQ4X:
case FILTER_NTSC:
scale = 8;
break;
default:
break;
}
#endif
#endif
scale = 2;
video_info_t video = {
.width = (g_settings.video.fullscreen) ? g_settings.video.fullscreen_x : (296 * g_settings.video.xscale),
@ -168,7 +164,7 @@ void init_video_input(void)
};
const input_driver_t *tmp = driver.input;
driver.video_data = driver.video->init(&video, &(driver.input));
driver.video_data = driver.video->init(&video, &driver.input);
if ( driver.video_data == NULL )
{

View File

@ -41,7 +41,7 @@ struct settings
bool smooth;
bool force_aspect;
char cg_shader_path[256];
char video_filter[64];
unsigned filter;
} video;
struct
@ -76,7 +76,6 @@ struct global
FILE *rom_file;
char savefile_name_srm[256];
char cg_shader_path[256];
char config_path[256];
};

102
gfx/gl.c
View File

@ -50,6 +50,7 @@ static const GLfloat tex_coords[] = {
static bool keep_aspect = true;
#ifdef HAVE_CG
static CGparameter cg_mvp_matrix;
static bool cg_active = false;
#endif
static GLuint gl_width = 0, gl_height = 0;
typedef struct gl
@ -214,7 +215,8 @@ static void GLFWCALL resize(int width, int height)
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
#ifdef HAVE_CG
cgGLSetStateMatrixParameter(cg_mvp_matrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
if (cg_active)
cgGLSetStateMatrixParameter(cg_mvp_matrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
#endif
gl_width = out_width;
gl_height = out_height;
@ -258,13 +260,16 @@ static bool gl_frame(void *data, const uint16_t* frame, int width, int height, i
glClear(GL_COLOR_BUFFER_BIT);
#if HAVE_CG
cgGLSetParameter2f(gl->cg_video_size, width, height);
cgGLSetParameter2f(gl->cg_texture_size, gl->tex_w, gl->tex_h);
cgGLSetParameter2f(gl->cg_output_size, gl_width, gl_height);
if (cg_active)
{
cgGLSetParameter2f(gl->cg_video_size, width, height);
cgGLSetParameter2f(gl->cg_texture_size, gl->tex_w, gl->tex_h);
cgGLSetParameter2f(gl->cg_output_size, gl_width, gl_height);
cgGLSetParameter2f(gl->cg_Vvideo_size, width, height);
cgGLSetParameter2f(gl->cg_Vtexture_size, gl->tex_w, gl->tex_h);
cgGLSetParameter2f(gl->cg_Voutput_size, gl_width, gl_height);
cgGLSetParameter2f(gl->cg_Vvideo_size, width, height);
cgGLSetParameter2f(gl->cg_Vtexture_size, gl->tex_w, gl->tex_h);
cgGLSetParameter2f(gl->cg_Voutput_size, gl_width, gl_height);
}
#endif
if (width != gl->last_width || height != gl->last_height) // res change. need to clear out texture.
@ -305,7 +310,8 @@ static void gl_free(void *data)
{
gl_t *gl = data;
#ifdef HAVE_CG
cgDestroyContext(gl->cgCtx);
if (cg_active)
cgDestroyContext(gl->cgCtx);
#endif
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
@ -327,7 +333,7 @@ static void gl_set_nonblock_state(void *data, bool state)
static void* gl_init(video_info_t *video, const input_driver_t **input)
{
gl_t *gl = malloc(sizeof(gl_t));
gl_t *gl = calloc(1, sizeof(gl_t));
if ( gl == NULL )
return NULL;
@ -394,44 +400,50 @@ static void* gl_init(video_info_t *video, const input_driver_t **input)
gl->last_height = gl->tex_h;
#ifdef HAVE_CG
gl->cgCtx = cgCreateContext();
if (gl->cgCtx == NULL)
cg_active = false;
if (strlen(g_settings.video.cg_shader_path) > 0)
{
fprintf(stderr, "Failed to create Cg context\n");
goto error;
}
gl->cgFProf = cgGLGetLatestProfile(CG_GL_FRAGMENT);
gl->cgVProf = cgGLGetLatestProfile(CG_GL_VERTEX);
if (gl->cgFProf == CG_PROFILE_UNKNOWN || gl->cgVProf == CG_PROFILE_UNKNOWN)
{
fprintf(stderr, "Invalid profile type\n");
goto error;
}
cgGLSetOptimalOptions(gl->cgFProf);
cgGLSetOptimalOptions(gl->cgVProf);
gl->cgFPrg = cgCreateProgramFromFile(gl->cgCtx, CG_SOURCE, g_settings.video.cg_shader_path, gl->cgFProf, "main_fragment", 0);
gl->cgVPrg = cgCreateProgramFromFile(gl->cgCtx, CG_SOURCE, g_settings.video.cg_shader_path, gl->cgVProf, "main_vertex", 0);
if (gl->cgFPrg == NULL || gl->cgVPrg == NULL)
{
CGerror err = cgGetError();
fprintf(stderr, "CG error: %s\n", cgGetErrorString(err));
goto error;
}
cgGLLoadProgram(gl->cgFPrg);
cgGLLoadProgram(gl->cgVPrg);
cgGLEnableProfile(gl->cgFProf);
cgGLEnableProfile(gl->cgVProf);
cgGLBindProgram(gl->cgFPrg);
cgGLBindProgram(gl->cgVPrg);
gl->cgCtx = cgCreateContext();
if (gl->cgCtx == NULL)
{
fprintf(stderr, "Failed to create Cg context\n");
goto error;
}
gl->cgFProf = cgGLGetLatestProfile(CG_GL_FRAGMENT);
gl->cgVProf = cgGLGetLatestProfile(CG_GL_VERTEX);
if (gl->cgFProf == CG_PROFILE_UNKNOWN || gl->cgVProf == CG_PROFILE_UNKNOWN)
{
fprintf(stderr, "Invalid profile type\n");
goto error;
}
cgGLSetOptimalOptions(gl->cgFProf);
cgGLSetOptimalOptions(gl->cgVProf);
puts(g_settings.video.cg_shader_path);
gl->cgFPrg = cgCreateProgramFromFile(gl->cgCtx, CG_SOURCE, g_settings.video.cg_shader_path, gl->cgFProf, "main_fragment", 0);
gl->cgVPrg = cgCreateProgramFromFile(gl->cgCtx, CG_SOURCE, g_settings.video.cg_shader_path, gl->cgVProf, "main_vertex", 0);
if (gl->cgFPrg == NULL || gl->cgVPrg == NULL)
{
CGerror err = cgGetError();
fprintf(stderr, "CG error: %s\n", cgGetErrorString(err));
goto error;
}
cgGLLoadProgram(gl->cgFPrg);
cgGLLoadProgram(gl->cgVPrg);
cgGLEnableProfile(gl->cgFProf);
cgGLEnableProfile(gl->cgVProf);
cgGLBindProgram(gl->cgFPrg);
cgGLBindProgram(gl->cgVPrg);
gl->cg_video_size = cgGetNamedParameter(gl->cgFPrg, "IN.video_size");
gl->cg_texture_size = cgGetNamedParameter(gl->cgFPrg, "IN.texture_size");
gl->cg_output_size = cgGetNamedParameter(gl->cgFPrg, "IN.output_size");
gl->cg_Vvideo_size = cgGetNamedParameter(gl->cgVPrg, "IN.video_size");
gl->cg_Vtexture_size = cgGetNamedParameter(gl->cgVPrg, "IN.texture_size");
gl->cg_Voutput_size = cgGetNamedParameter(gl->cgVPrg, "IN.output_size");
cg_mvp_matrix = cgGetNamedParameter(gl->cgVPrg, "modelViewProj");
cgGLSetStateMatrixParameter(cg_mvp_matrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
gl->cg_video_size = cgGetNamedParameter(gl->cgFPrg, "IN.video_size");
gl->cg_texture_size = cgGetNamedParameter(gl->cgFPrg, "IN.texture_size");
gl->cg_output_size = cgGetNamedParameter(gl->cgFPrg, "IN.output_size");
gl->cg_Vvideo_size = cgGetNamedParameter(gl->cgVPrg, "IN.video_size");
gl->cg_Vtexture_size = cgGetNamedParameter(gl->cgVPrg, "IN.texture_size");
gl->cg_Voutput_size = cgGetNamedParameter(gl->cgVPrg, "IN.output_size");
cg_mvp_matrix = cgGetNamedParameter(gl->cgVPrg, "modelViewProj");
cgGLSetStateMatrixParameter(cg_mvp_matrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
cg_active = true;
}
#endif
*input = &input_glfw;

23
hqflt/filters.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef __FILTERS_H
#define __FILTERS_H
#ifdef HAVE_FILTER
#include "pastlib.h"
#include "grayscale.h"
#include "bleed.h"
#include "ntsc.h"
#define FILTER_HQ2X 1
#define FILTER_HQ4X 2
#define FILTER_GRAYSCALE 3
#define FILTER_BLEED 4
#define FILTER_NTSC 5
#define FILTER_HQ2X_STR "hq2x"
#define FILTER_HQ4X_STR "hq4x"
#define FILTER_GRAYSCALE_STR "grayscale"
#define FILTER_BLEED_STR "bleed"
#define FILTER_NTSC_STR "ntsc"
#endif
#endif

View File

@ -56,10 +56,6 @@ static void set_defaults(void)
g_settings.video.vsync = vsync;
g_settings.video.smooth = video_smooth;
g_settings.video.force_aspect = force_aspect;
#if HAVE_CG
strncpy(g_settings.video.cg_shader_path, DEFAULT_CG_SHADER, sizeof(g_settings.video.cg_shader_path) - 1);
#endif
strncpy(g_settings.video.video_filter, "foo", sizeof(g_settings.video.video_filter) - 1);
g_settings.audio.enable = audio_enable;
g_settings.audio.out_rate = out_rate;
@ -86,25 +82,35 @@ void parse_config(void)
memset(&g_settings, 0, sizeof(struct settings));
config_file_t *conf = NULL;
const char *xdg = getenv("XDG_CONFIG_HOME");
if (xdg)
if (strlen(g_extern.config_path) > 0)
{
char conf_path[strlen(xdg) + strlen("/ssnes ")];
strcpy(conf_path, xdg);
strcat(conf_path, "/ssnes");
conf = config_file_new(conf_path);
conf = config_file_new(g_extern.config_path);
if (!conf)
{
SSNES_ERR("Couldn't find config at path: \"%s\"\n", g_extern.config_path);
exit(1);
}
}
else
{
const char *xdg = getenv("XDG_CONFIG_HOME");
const char *home = getenv("HOME");
if (home)
if (xdg)
{
char conf_path[strlen(xdg) + strlen("/ssnes ")];
strcpy(conf_path, xdg);
strcat(conf_path, "/ssnes");
conf = config_file_new(conf_path);
}
else if (home)
{
char conf_path[strlen(home) + strlen("/.ssnesrc ")];
strcpy(conf_path, xdg);
strcat(conf_path, "/.ssnesrc");
conf = config_file_new(conf_path);
}
else // Try /etc/ssnes.conf as a final test ...
conf = config_file_new("/etc/ssnes.conf");
}
set_defaults();
@ -138,17 +144,43 @@ void parse_config(void)
if (config_get_bool(conf, "video_force_aspect", &tmp_bool))
g_settings.video.force_aspect = tmp_bool;
if (config_get_string(conf, "video_cg_shader_path", &tmp_str))
if (config_get_string(conf, "video_cg_shader", &tmp_str))
{
strncpy(g_settings.video.cg_shader_path, tmp_str, sizeof(g_settings.video.cg_shader_path) - 1);
free(tmp_str);
}
if (config_get_string(conf, "video_video_filter", &tmp_str))
#ifdef HAVE_FILTER
if (config_get_string(conf, "video_filter", &tmp_str))
{
strncpy(g_settings.video.video_filter, tmp_str, sizeof(g_settings.video.video_filter) - 1);
unsigned filter = 0;
if (strcasecmp(FILTER_HQ2X_STR, tmp_str) == 0)
filter = FILTER_HQ2X;
else if (strcasecmp(FILTER_HQ4X_STR, tmp_str) == 0)
filter = FILTER_HQ4X;
else if (strcasecmp(FILTER_GRAYSCALE_STR, tmp_str) == 0)
filter = FILTER_GRAYSCALE;
else if (strcasecmp(FILTER_BLEED_STR, tmp_str) == 0)
filter = FILTER_BLEED;
else if (strcasecmp(FILTER_NTSC_STR, tmp_str) == 0)
filter = FILTER_NTSC;
else
{
SSNES_ERR(
"Invalid filter... Valid filters are:\n"
"\t%s\n"
"\t%s\n"
"\t%s\n"
"\t%s\n"
"\t%s\n",
FILTER_HQ2X_STR, FILTER_HQ4X_STR, FILTER_GRAYSCALE_STR,
FILTER_BLEED, FILTER_NTSC);
exit(1);
}
free(tmp_str);
}
#endif
// Input Settings.
if (config_get_double(conf, "input_axis_threshold", &tmp_double))
@ -178,8 +210,8 @@ void parse_config(void)
if (config_get_int(conf, "audio_src_quality", &tmp_int))
{
int quals[] = {SRC_ZERO_ORDER_HOLD, SRC_LINEAR, SRC_SINC_FASTEST,
SRC_SINC_MEDIUM_QUALITY, SRC_SINC_BEST_QUALITY};
int quals[] = { SRC_ZERO_ORDER_HOLD, SRC_LINEAR, SRC_SINC_FASTEST,
SRC_SINC_MEDIUM_QUALITY, SRC_SINC_BEST_QUALITY };
if (tmp_int > 0 && tmp_int < 6)
g_settings.audio.src_quality = quals[tmp_int];

93
ssnes.c
View File

@ -26,10 +26,7 @@
#include <getopt.h>
#include "driver.h"
#include "file.h"
#include "hqflt/pastlib.h"
#include "hqflt/grayscale.h"
#include "hqflt/bleed.h"
#include "hqflt/ntsc.h"
#include "hqflt/filters.h"
#include "general.h"
struct global g_extern = {
@ -61,7 +58,7 @@ void set_fast_forward_button(bool new_button_state)
old_button_state = new_button_state;
}
#if VIDEO_FILTER != FILTER_NONE
#ifdef HAVE_FILTER
static inline void process_frame (uint16_t * restrict out, const uint16_t * restrict in, unsigned width, unsigned height)
{
int pitch = 1024;
@ -85,48 +82,46 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
if ( !g_extern.video_active )
return;
#if 0
#if VIDEO_FILTER == FILTER_HQ2X
uint16_t outputHQ2x[width * height * 2 * 2];
#elif VIDEO_FILTER == FILTER_HQ4X
uint16_t outputHQ4x[width * height * 4 * 4];
#elif VIDEO_FILTER == FILTER_NTSC
uint16_t output_ntsc[SNES_NTSC_OUT_WIDTH(width) * height];
#endif
#if VIDEO_FILTER != FILTER_NONE
#ifdef HAVE_FILTER
uint16_t output_filter[width * height * 4 * 4];
uint16_t output[width * height];
process_frame(output, data, width, height);
#endif
#if VIDEO_FILTER == FILTER_HQ2X
ProcessHQ2x(output, outputHQ2x);
if ( !driver.video->frame(driver.video_data, outputHQ2x, width << 1, height << 1, width << 2) )
video_active = false;
#elif VIDEO_FILTER == FILTER_HQ4X
ProcessHQ4x(output, outputHQ4x);
if ( !driver.video->frame(driver.video_data, outputHQ4x, width << 2, height << 2, width << 3) )
video_active = false;
#elif VIDEO_FILTER == FILTER_GRAYSCALE
grayscale_filter(output, width, height);
if ( !driver.video->frame(driver.video_data, output, width, height, width << 1) )
video_active = false;
#elif VIDEO_FILTER == FILTER_BLEED
bleed_filter(output, width, height);
if ( !driver.video->frame(driver.video_data, output, width, height, width << 1) )
video_active = false;
#elif VIDEO_FILTER == FILTER_NTSC
ntsc_filter(output_ntsc, output, width, height);
if ( !driver.video->frame(driver.video_data, output_ntsc, SNES_NTSC_OUT_WIDTH(width), height, SNES_NTSC_OUT_WIDTH(width) << 1) )
video_active = false;
switch (g_settings.video.filter)
{
case FILTER_HQ2X:
ProcessHQ2x(output, output_filter);
if ( !driver.video->frame(driver.video_data, output_filter, width << 1, height << 1, width << 2) )
video_active = false;
break;
case FILTER_HQ4X:
ProcessHQ4x(output, output_filter);
if ( !driver.video->frame(driver.video_data, output_filter, width << 2, height << 2, width << 3) )
video_active = false;
break;
case FILTER_GRAYSCALE:
grayscale_filter(output, width, height);
if ( !driver.video->frame(driver.video_data, output, width, height, width << 1) )
video_active = false;
break;
case FILTER_BLEED:
bleed_filter(output, width, height);
if ( !driver.video->frame(driver.video_data, output, width, height, width << 1) )
video_active = false;
break;
case FILTER_NTSC:
ntsc_filter(output_filter, output, width, height);
if ( !driver.video->frame(driver.video_data, output_filter, SNES_NTSC_OUT_WIDTH(width), height, SNES_NTSC_OUT_WIDTH(width) << 1) )
video_active = false;
break;
default:
if ( !driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048) )
g_extern.video_active = false;
}
#else
if ( !driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048) )
g_extern.video_active = false;
#endif
#endif
if ( !driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048) )
g_extern.video_active = false;
}
static void audio_sample(uint16_t left, uint16_t right)
@ -200,9 +195,6 @@ static void print_help(void)
puts("\t-h/--help: Show this help message");
puts("\t-s/--save: Path for save file (*.srm). Required when rom is input from stdin");
puts("\t-c/--config: Path for config file. Defaults to $XDG_CONFIG_HOME/ssnes");
#ifdef HAVE_CG
puts("\t-f/--shader: Path to Cg shader. Will be compiled at runtime.\n");
#endif
puts("\t-v/--verbose: Verbose logging");
}
@ -219,18 +211,11 @@ static void parse_input(int argc, char *argv[])
{ "save", 1, NULL, 's' },
{ "verbose", 0, NULL, 'v' },
{ "config", 0, NULL, 'c' },
#ifdef HAVE_CG
{ "shader", 1, NULL, 'f' },
#endif
{ NULL, 0, NULL, 0 }
};
int option_index = 0;
#ifdef HAVE_CG
char optstring[] = "hs:vf:c:";
#else
char optstring[] = "hs:vc:";
#endif
for(;;)
{
int c = getopt_long(argc, argv, optstring, opts, &option_index);
@ -249,12 +234,6 @@ static void parse_input(int argc, char *argv[])
g_extern.savefile_name_srm[sizeof(g_extern.savefile_name_srm)-1] = '\0';
break;
#ifdef HAVE_CG
case 'f':
strncpy(g_extern.cg_shader_path, optarg, sizeof(g_extern.cg_shader_path) - 1);
break;
#endif
case 'v':
g_extern.verbose = true;
break;
@ -307,8 +286,8 @@ static void parse_input(int argc, char *argv[])
int main(int argc, char *argv[])
{
snes_init();
parse_config();
parse_input(argc, argv);
parse_config();
void *rom_buf;
ssize_t rom_len = 0;