Start working on Cg preset spec.
This commit is contained in:
parent
70000607a2
commit
993bdfb75f
323
gfx/shader_cg.c
323
gfx/shader_cg.c
|
@ -20,6 +20,8 @@
|
||||||
#include <Cg/cgGL.h>
|
#include <Cg/cgGL.h>
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "strl.h"
|
||||||
|
#include "conf/config_file.h"
|
||||||
|
|
||||||
// Used when we call deactivate() since just unbinding the program didn't seem to work... :(
|
// Used when we call deactivate() since just unbinding the program didn't seem to work... :(
|
||||||
static const char* stock_cg_program =
|
static const char* stock_cg_program =
|
||||||
|
@ -41,17 +43,9 @@ static const char* stock_cg_program =
|
||||||
" otexCoord = texCoord;"
|
" otexCoord = texCoord;"
|
||||||
"}"
|
"}"
|
||||||
""
|
""
|
||||||
""
|
"float4 main_fragment(float2 tex : TEXCOORD0, uniform sampler2D s0 : TEXUNIT0) : COLOR"
|
||||||
"struct output "
|
|
||||||
"{"
|
"{"
|
||||||
" float4 color : COLOR;"
|
" return tex2D(s0, tex);"
|
||||||
"};"
|
|
||||||
""
|
|
||||||
"output main_fragment(float2 texCoord : TEXCOORD0, uniform sampler2D decal : TEXUNIT0) "
|
|
||||||
"{"
|
|
||||||
" output OUT;"
|
|
||||||
" OUT.color = tex2D(decal, texCoord);"
|
|
||||||
" return OUT;"
|
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,10 +65,18 @@ struct cg_program
|
||||||
CGparameter mvp;
|
CGparameter mvp;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct cg_program prg[3];
|
#define FILTER_UNSPEC 0
|
||||||
|
#define FILTER_LINEAR 1
|
||||||
|
#define FILTER_NEAREST 2
|
||||||
|
|
||||||
|
#define MAX_SHADERS 16
|
||||||
|
static struct cg_program prg[MAX_SHADERS];
|
||||||
static bool cg_active = false;
|
static bool cg_active = false;
|
||||||
static CGprofile cgVProf, cgFProf;
|
static CGprofile cgVProf, cgFProf;
|
||||||
static unsigned active_index = 0;
|
static unsigned active_index = 0;
|
||||||
|
static unsigned cg_shader_num = 0;
|
||||||
|
static struct gl_fbo_scale cg_scale[MAX_SHADERS];
|
||||||
|
static unsigned fbo_smooth[MAX_SHADERS];
|
||||||
|
|
||||||
void gl_cg_set_proj_matrix(void)
|
void gl_cg_set_proj_matrix(void)
|
||||||
{
|
{
|
||||||
|
@ -106,14 +108,253 @@ void gl_cg_deinit(void)
|
||||||
if (cg_active)
|
if (cg_active)
|
||||||
cgDestroyContext(cgCtx);
|
cgDestroyContext(cgCtx);
|
||||||
cg_active = false;
|
cg_active = false;
|
||||||
|
cg_shader_num = 0;
|
||||||
|
memset(prg, 0, sizeof(prg));
|
||||||
|
memset(cg_scale, 0, sizeof(cg_scale));
|
||||||
|
memset(fbo_smooth, 0, sizeof(fbo_smooth));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gl_cg_init(const char *path)
|
static bool load_plain(const char *path)
|
||||||
{
|
{
|
||||||
SSNES_LOG("Loading Cg file: %s\n", path);
|
SSNES_LOG("Loading Cg file: %s\n", path);
|
||||||
if (strlen(g_settings.video.second_pass_shader) > 0)
|
if (strlen(g_settings.video.second_pass_shader) > 0)
|
||||||
SSNES_LOG("Loading 2nd pass: %s\n", g_settings.video.second_pass_shader);
|
SSNES_LOG("Loading 2nd pass: %s\n", g_settings.video.second_pass_shader);
|
||||||
|
|
||||||
|
prg[0].fprg = cgCreateProgram(cgCtx, CG_SOURCE, stock_cg_program, cgFProf, "main_fragment", 0);
|
||||||
|
prg[0].vprg = cgCreateProgram(cgCtx, CG_SOURCE, stock_cg_program, cgVProf, "main_vertex", 0);
|
||||||
|
|
||||||
|
prg[1].fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, path, cgFProf, "main_fragment", 0);
|
||||||
|
prg[1].vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, path, cgVProf, "main_vertex", 0);
|
||||||
|
|
||||||
|
if (strlen(g_settings.video.second_pass_shader) > 0)
|
||||||
|
{
|
||||||
|
prg[2].fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, g_settings.video.second_pass_shader, cgFProf, "main_fragment", 0);
|
||||||
|
prg[2].vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, g_settings.video.second_pass_shader, cgVProf, "main_vertex", 0);
|
||||||
|
cg_shader_num = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prg[2] = prg[0];
|
||||||
|
cg_shader_num = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if (prg[i].fprg == NULL || prg[i].vprg == NULL)
|
||||||
|
{
|
||||||
|
CGerror err = cgGetError();
|
||||||
|
SSNES_ERR("CG error: %s\n", cgGetErrorString(err));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cgGLLoadProgram(prg[i].fprg);
|
||||||
|
cgGLLoadProgram(prg[i].vprg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool load_preset(const char *path)
|
||||||
|
{
|
||||||
|
// Create passthrough shader.
|
||||||
|
prg[0].fprg = cgCreateProgram(cgCtx, CG_SOURCE, stock_cg_program, cgFProf, "main_fragment", 0);
|
||||||
|
prg[0].vprg = cgCreateProgram(cgCtx, CG_SOURCE, stock_cg_program, cgVProf, "main_vertex", 0);
|
||||||
|
if (!prg[0].fprg || !prg[0].vprg)
|
||||||
|
{
|
||||||
|
SSNES_ERR("Failed to compile passthrough shader, is something wrong with your environment?\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SSNES_LOG("Loading Cg meta-shader: %s\n", path);
|
||||||
|
config_file_t *conf = config_file_new(path);
|
||||||
|
if (!conf)
|
||||||
|
{
|
||||||
|
SSNES_ERR("Failed to load preset.\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shaders;
|
||||||
|
if (config_get_int(conf, "shaders", &shaders))
|
||||||
|
{
|
||||||
|
SSNES_ERR("Cannot find \"shaders\" param.\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shaders < 1)
|
||||||
|
{
|
||||||
|
SSNES_ERR("Need to define at least 1 shader!\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
cg_shader_num = shaders;
|
||||||
|
|
||||||
|
// Check filter params.
|
||||||
|
for (unsigned i = 0; i < shaders; i++)
|
||||||
|
{
|
||||||
|
bool smooth;
|
||||||
|
char filter_name_buf[64];
|
||||||
|
snprintf(filter_name_buf, sizeof(filter_name_buf), "filter_linear%u", i);
|
||||||
|
if (config_get_bool(conf, filter_name_buf, &smooth))
|
||||||
|
fbo_smooth[i + 1] = smooth ? FILTER_LINEAR : FILTER_NEAREST;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bigass for-loop ftw. Check scaling params.
|
||||||
|
for (unsigned i = 0; i < shaders; i++)
|
||||||
|
{
|
||||||
|
char *scale_type;
|
||||||
|
char scale_name_buf[64];
|
||||||
|
snprintf(scale_name_buf, sizeof(scale_name_buf), "scale_type%u", i);
|
||||||
|
if (config_get_string(conf, scale_name_buf, &scale_type))
|
||||||
|
{
|
||||||
|
char attr_name_buf[64];
|
||||||
|
double fattr;
|
||||||
|
int iattr;
|
||||||
|
struct gl_fbo_scale *scale = &cg_scale[i + 1]; // Shader 0 is passthrough shader. Start at 1.
|
||||||
|
|
||||||
|
scale->valid = true;
|
||||||
|
scale->type_x = SSNES_SCALE_INPUT;
|
||||||
|
scale->type_y = SSNES_SCALE_INPUT;
|
||||||
|
scale->scale_x = SSNES_SCALE_INPUT;
|
||||||
|
scale->scale_y = SSNES_SCALE_INPUT;
|
||||||
|
|
||||||
|
// Check source scale.
|
||||||
|
if (strcmp(scale_type, "source") == 0)
|
||||||
|
{
|
||||||
|
snprintf(attr_name_buf, sizeof(attr_name_buf), "scale%u", i);
|
||||||
|
if (config_get_double(conf, attr_name_buf, &fattr))
|
||||||
|
{
|
||||||
|
scale->scale_x = fattr;
|
||||||
|
scale->scale_y = fattr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snprintf(attr_name_buf, sizeof(attr_name_buf), "scale_x%u", i);
|
||||||
|
if (config_get_double(conf, attr_name_buf, &fattr))
|
||||||
|
scale->scale_x = fattr;
|
||||||
|
|
||||||
|
snprintf(attr_name_buf, sizeof(attr_name_buf), "scale_y%u", i);
|
||||||
|
if (config_get_double(conf, attr_name_buf, &fattr))
|
||||||
|
scale->scale_y = fattr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Viewport scale.
|
||||||
|
else if (strcmp(scale_type, "viewport") == 0)
|
||||||
|
{
|
||||||
|
snprintf(attr_name_buf, sizeof(attr_name_buf), "scale%u", i);
|
||||||
|
if (config_get_double(conf, attr_name_buf, &fattr))
|
||||||
|
{
|
||||||
|
scale->scale_x = fattr;
|
||||||
|
scale->scale_y = fattr;
|
||||||
|
scale->type_x = SSNES_SCALE_VIEWPORT;
|
||||||
|
scale->type_y = SSNES_SCALE_VIEWPORT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snprintf(attr_name_buf, sizeof(attr_name_buf), "scale_x%u", i);
|
||||||
|
if (config_get_double(conf, attr_name_buf, &fattr))
|
||||||
|
{
|
||||||
|
scale->scale_x = fattr;
|
||||||
|
scale->type_x = SSNES_SCALE_VIEWPORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(attr_name_buf, sizeof(attr_name_buf), "scale_y%u", i);
|
||||||
|
if (config_get_double(conf, attr_name_buf, &fattr))
|
||||||
|
{
|
||||||
|
scale->scale_y = fattr;
|
||||||
|
scale->type_y = SSNES_SCALE_VIEWPORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Absolute pixel scale.
|
||||||
|
else if (strcmp(scale_type, "absolute") == 0)
|
||||||
|
{
|
||||||
|
snprintf(attr_name_buf, sizeof(attr_name_buf), "scale%u", i);
|
||||||
|
if (config_get_int(conf, attr_name_buf, &iattr))
|
||||||
|
{
|
||||||
|
scale->abs_x = iattr;
|
||||||
|
scale->abs_y = iattr;
|
||||||
|
scale->type_x = SSNES_SCALE_ABSOLUTE;
|
||||||
|
scale->type_y = SSNES_SCALE_ABSOLUTE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snprintf(attr_name_buf, sizeof(attr_name_buf), "scale_x%u", i);
|
||||||
|
if (config_get_int(conf, attr_name_buf, &iattr))
|
||||||
|
{
|
||||||
|
scale->abs_x = iattr;
|
||||||
|
scale->type_x = SSNES_SCALE_ABSOLUTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(attr_name_buf, sizeof(attr_name_buf), "scale_y%u", i);
|
||||||
|
if (config_get_int(conf, attr_name_buf, &iattr))
|
||||||
|
{
|
||||||
|
scale->abs_y = iattr;
|
||||||
|
scale->type_y = SSNES_SCALE_ABSOLUTE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SSNES_ERR("Invalid attribute: \"%s\"\n", scale_type);
|
||||||
|
free(scale_type);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(scale_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally load shaders :)
|
||||||
|
for (unsigned i = 0; i < shaders; i++)
|
||||||
|
{
|
||||||
|
char *shader_path;
|
||||||
|
char attr_buf[64];
|
||||||
|
char path_buf[512];
|
||||||
|
|
||||||
|
snprintf(attr_buf, sizeof(attr_buf), "shader%u", i);
|
||||||
|
if (config_get_string(conf, attr_buf, &shader_path))
|
||||||
|
{
|
||||||
|
strlcpy(path_buf, path, sizeof(path_buf));
|
||||||
|
strlcat(path_buf, "/", sizeof(path_buf));
|
||||||
|
strlcat(path_buf, shader_path, sizeof(path_buf));
|
||||||
|
free(shader_path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SSNES_ERR("Didn't find shader path in config ...\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
SSNES_LOG("Loading Cg shader: \"%s\".\n", path_buf);
|
||||||
|
|
||||||
|
struct cg_program *prog = &prg[i + 1];
|
||||||
|
prog->fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, path_buf, cgFProf, "main_fragment", 0);
|
||||||
|
prog->vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, path_buf, cgVProf, "main_vertex", 0);
|
||||||
|
|
||||||
|
if (!prog->fprg || !prog->vprg)
|
||||||
|
{
|
||||||
|
CGerror err = cgGetError();
|
||||||
|
SSNES_ERR("CG error: %s\n", cgGetErrorString(err));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
cgGLLoadProgram(prog->fprg);
|
||||||
|
cgGLLoadProgram(prog->vprg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Load textures ...
|
||||||
|
|
||||||
|
config_file_free(conf);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (conf)
|
||||||
|
config_file_free(conf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gl_cg_init(const char *path)
|
||||||
|
{
|
||||||
cgCtx = cgCreateContext();
|
cgCtx = cgCreateContext();
|
||||||
if (cgCtx == NULL)
|
if (cgCtx == NULL)
|
||||||
{
|
{
|
||||||
|
@ -131,38 +372,21 @@ bool gl_cg_init(const char *path)
|
||||||
cgGLSetOptimalOptions(cgFProf);
|
cgGLSetOptimalOptions(cgFProf);
|
||||||
cgGLSetOptimalOptions(cgVProf);
|
cgGLSetOptimalOptions(cgVProf);
|
||||||
|
|
||||||
|
if (strstr(path, ".cgp"))
|
||||||
prg[0].fprg = cgCreateProgram(cgCtx, CG_SOURCE, stock_cg_program, cgFProf, "main_fragment", 0);
|
|
||||||
prg[0].vprg = cgCreateProgram(cgCtx, CG_SOURCE, stock_cg_program, cgVProf, "main_vertex", 0);
|
|
||||||
|
|
||||||
prg[1].fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, path, cgFProf, "main_fragment", 0);
|
|
||||||
prg[1].vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, path, cgVProf, "main_vertex", 0);
|
|
||||||
|
|
||||||
if (strlen(g_settings.video.second_pass_shader) > 0)
|
|
||||||
{
|
{
|
||||||
prg[2].fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, g_settings.video.second_pass_shader, cgFProf, "main_fragment", 0);
|
if (!load_preset(path))
|
||||||
prg[2].vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, g_settings.video.second_pass_shader, cgVProf, "main_vertex", 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
prg[2] = prg[0];
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
if (prg[i].fprg == NULL || prg[i].vprg == NULL)
|
|
||||||
{
|
|
||||||
CGerror err = cgGetError();
|
|
||||||
SSNES_ERR("CG error: %s\n", cgGetErrorString(err));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
cgGLLoadProgram(prg[i].fprg);
|
{
|
||||||
cgGLLoadProgram(prg[i].vprg);
|
if (!load_plain(path))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cgGLEnableProfile(cgFProf);
|
cgGLEnableProfile(cgFProf);
|
||||||
cgGLEnableProfile(cgVProf);
|
cgGLEnableProfile(cgVProf);
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++)
|
for (unsigned i = 0; i < cg_shader_num; i++)
|
||||||
{
|
{
|
||||||
cgGLBindProgram(prg[i].fprg);
|
cgGLBindProgram(prg[i].fprg);
|
||||||
cgGLBindProgram(prg[i].vprg);
|
cgGLBindProgram(prg[i].vprg);
|
||||||
|
@ -174,7 +398,7 @@ bool gl_cg_init(const char *path)
|
||||||
prg[i].vid_size_v = cgGetNamedParameter(prg[i].vprg, "IN.video_size");
|
prg[i].vid_size_v = cgGetNamedParameter(prg[i].vprg, "IN.video_size");
|
||||||
prg[i].tex_size_v = cgGetNamedParameter(prg[i].vprg, "IN.texture_size");
|
prg[i].tex_size_v = cgGetNamedParameter(prg[i].vprg, "IN.texture_size");
|
||||||
prg[i].out_size_v = cgGetNamedParameter(prg[i].vprg, "IN.output_size");
|
prg[i].out_size_v = cgGetNamedParameter(prg[i].vprg, "IN.output_size");
|
||||||
prg[i].frame_cnt_v = cgGetNamedParameter(prg[i].fprg, "IN.frame_count");
|
prg[i].frame_cnt_v = cgGetNamedParameter(prg[i].vprg, "IN.frame_count");
|
||||||
prg[i].mvp = cgGetNamedParameter(prg[i].vprg, "modelViewProj");
|
prg[i].mvp = cgGetNamedParameter(prg[i].vprg, "modelViewProj");
|
||||||
cgGLSetStateMatrixParameter(prg[i].mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
|
cgGLSetStateMatrixParameter(prg[i].mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
|
||||||
}
|
}
|
||||||
|
@ -188,7 +412,7 @@ bool gl_cg_init(const char *path)
|
||||||
|
|
||||||
void gl_cg_use(unsigned index)
|
void gl_cg_use(unsigned index)
|
||||||
{
|
{
|
||||||
if (cg_active)
|
if (cg_active && prg[index].vprg && prg[index].fprg)
|
||||||
{
|
{
|
||||||
active_index = index;
|
active_index = index;
|
||||||
cgGLBindProgram(prg[index].vprg);
|
cgGLBindProgram(prg[index].vprg);
|
||||||
|
@ -199,27 +423,28 @@ void gl_cg_use(unsigned index)
|
||||||
unsigned gl_cg_num(void)
|
unsigned gl_cg_num(void)
|
||||||
{
|
{
|
||||||
if (cg_active)
|
if (cg_active)
|
||||||
{
|
return cg_shader_num;
|
||||||
if (prg[0].fprg == prg[2].fprg)
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gl_cg_filter_type(unsigned index, bool *smooth)
|
bool gl_cg_filter_type(unsigned index, bool *smooth)
|
||||||
{
|
{
|
||||||
(void)index;
|
if (cg_active)
|
||||||
(void)smooth;
|
{
|
||||||
// We don't really care since .cg doesn't have those kinds of semantics by itself ...
|
if (fbo_smooth[index] == FILTER_UNSPEC)
|
||||||
|
return false;
|
||||||
|
*smooth = (fbo_smooth[index] == FILTER_LINEAR);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gl_cg_shader_scale(unsigned index, struct gl_fbo_scale *scale)
|
void gl_cg_shader_scale(unsigned index, struct gl_fbo_scale *scale)
|
||||||
{
|
{
|
||||||
(void)index;
|
if (cg_active)
|
||||||
// We don't really care since .cg doesn't have those kinds of semantics by itself ...
|
*scale = cg_scale[index];
|
||||||
|
else
|
||||||
scale->valid = false;
|
scale->valid = false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue