mirror of https://github.com/snes9xgit/snes9x.git
Slang: Implement feedback support. See below.
This uses a complex workaround because we normally draw the last pass straight to the screen. Now, only in the event that feedback is enabled and only if the last pass uses it, we draw to a texture and use glBlitFramebuffer to draw to the screen (saved_framebuffer) instead.
This commit is contained in:
parent
58e1bfadfa
commit
8c8805da40
|
@ -19,7 +19,7 @@ static const GLfloat mvp_ortho[16] = { 2.0f, 0.0f, 0.0f, 0.0f,
|
||||||
0.0f, 0.0f, -1.0f, 0.0f,
|
0.0f, 0.0f, -1.0f, 0.0f,
|
||||||
-1.0f, -1.0f, 0.0f, 1.0f };
|
-1.0f, -1.0f, 0.0f, 1.0f };
|
||||||
|
|
||||||
static int scale_string_to_enum(const char *string, bool last)
|
static int scale_string_to_enum(const char *string)
|
||||||
{
|
{
|
||||||
if (!strcasecmp(string, "source"))
|
if (!strcasecmp(string, "source"))
|
||||||
{
|
{
|
||||||
|
@ -33,10 +33,8 @@ static int scale_string_to_enum(const char *string, bool last)
|
||||||
{
|
{
|
||||||
return GLSL_ABSOLUTE;
|
return GLSL_ABSOLUTE;
|
||||||
}
|
}
|
||||||
else if (last)
|
|
||||||
return GLSL_VIEWPORT;
|
|
||||||
else
|
else
|
||||||
return GLSL_SOURCE;
|
return GLSL_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *scale_enum_to_string(int val)
|
static const char *scale_enum_to_string(int val)
|
||||||
|
@ -50,7 +48,7 @@ static const char *scale_enum_to_string(int val)
|
||||||
case GLSL_ABSOLUTE:
|
case GLSL_ABSOLUTE:
|
||||||
return "absolute";
|
return "absolute";
|
||||||
default:
|
default:
|
||||||
return "source";
|
return "undefined";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,15 +150,15 @@ bool GLSLShader::load_shader_preset_file(char *filename)
|
||||||
{
|
{
|
||||||
sprintf(key, "::scale_type_x%u", i);
|
sprintf(key, "::scale_type_x%u", i);
|
||||||
const char* scaleTypeX = conf.GetString(key, "");
|
const char* scaleTypeX = conf.GetString(key, "");
|
||||||
pass.scale_type_x = scale_string_to_enum(scaleTypeX, i == shader_count - 1);
|
pass.scale_type_x = scale_string_to_enum(scaleTypeX);
|
||||||
|
|
||||||
sprintf(key, "::scale_type_y%u", i);
|
sprintf(key, "::scale_type_y%u", i);
|
||||||
const char* scaleTypeY = conf.GetString(key, "");
|
const char* scaleTypeY = conf.GetString(key, "");
|
||||||
pass.scale_type_y = scale_string_to_enum(scaleTypeY, i == shader_count - 1);
|
pass.scale_type_y = scale_string_to_enum(scaleTypeY);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int scale_type = scale_string_to_enum(scaleType, i == shader_count - 1);
|
int scale_type = scale_string_to_enum(scaleType);
|
||||||
pass.scale_type_x = scale_type;
|
pass.scale_type_x = scale_type;
|
||||||
pass.scale_type_y = scale_type;
|
pass.scale_type_y = scale_type;
|
||||||
}
|
}
|
||||||
|
@ -598,12 +596,17 @@ void GLSLShader::render(GLuint &orig,
|
||||||
pass[0].width = width;
|
pass[0].width = width;
|
||||||
pass[0].height = height;
|
pass[0].height = height;
|
||||||
|
|
||||||
for (int i = 1; i < (int)pass.size(); i++)
|
#ifdef USE_SLANG
|
||||||
{
|
if (using_slang && using_feedback)
|
||||||
GLuint tmp = pass[i].texture;
|
for (int i = 1; i < (int)pass.size(); i++)
|
||||||
pass[i].texture = pass[i].feedback_texture;
|
{
|
||||||
pass[i].feedback_texture = tmp;
|
if (!pass[i].uses_feedback)
|
||||||
}
|
continue;
|
||||||
|
GLuint tmp = pass[i].texture;
|
||||||
|
pass[i].texture = pass[i].feedback_texture;
|
||||||
|
pass[i].feedback_texture = tmp;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// loop through all real passes
|
// loop through all real passes
|
||||||
for (unsigned int i = 1; i < pass.size(); i++)
|
for (unsigned int i = 1; i < pass.size(); i++)
|
||||||
|
@ -622,7 +625,10 @@ void GLSLShader::render(GLuint &orig,
|
||||||
pass[i].width = viewport_width * pass[i].scale_x;
|
pass[i].width = viewport_width * pass[i].scale_x;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pass[i].width = viewport_width;
|
if (lastpass)
|
||||||
|
pass[i].width = viewport_width;
|
||||||
|
else
|
||||||
|
pass[i].width = pass[i - 1].width * pass[i].scale_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (pass[i].scale_type_y)
|
switch (pass[i].scale_type_y)
|
||||||
|
@ -640,7 +646,15 @@ void GLSLShader::render(GLuint &orig,
|
||||||
pass[i].height = viewport_height;
|
pass[i].height = viewport_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lastpass)
|
bool direct_lastpass = true;
|
||||||
|
#ifdef USE_SLANG
|
||||||
|
if (lastpass && using_feedback && pass[i].scale_type_x != GLSL_NONE &&
|
||||||
|
pass[i].scale_type_y != GLSL_NONE && pass[i].uses_feedback)
|
||||||
|
{
|
||||||
|
direct_lastpass = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!lastpass || !direct_lastpass)
|
||||||
{
|
{
|
||||||
// Output to a framebuffer texture
|
// Output to a framebuffer texture
|
||||||
glBindTexture(GL_TEXTURE_2D, pass[i].texture);
|
glBindTexture(GL_TEXTURE_2D, pass[i].texture);
|
||||||
|
@ -720,17 +734,42 @@ void GLSLShader::render(GLuint &orig,
|
||||||
glUseProgram(pass[i].program);
|
glUseProgram(pass[i].program);
|
||||||
#ifdef USE_SLANG
|
#ifdef USE_SLANG
|
||||||
if (using_slang)
|
if (using_slang)
|
||||||
slang_set_shader_vars(i);
|
slang_set_shader_vars(i, lastpass && direct_lastpass);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
set_shader_vars(i);
|
set_shader_vars(i, lastpass && direct_lastpass);
|
||||||
|
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
|
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
// reset vertex attribs set in set_shader_vars
|
|
||||||
#ifdef USE_SLANG
|
#ifdef USE_SLANG
|
||||||
|
if (lastpass && !direct_lastpass)
|
||||||
|
{
|
||||||
|
glBindTexture(GL_TEXTURE_2D, pass[i].texture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, pass[i].wrap_mode);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, pass[i].wrap_mode);
|
||||||
|
|
||||||
|
int out_x = 0, out_y = 0, out_width = 0, out_height = 0;
|
||||||
|
vpcallback (pass[i].width, pass[i].height,
|
||||||
|
viewport_x, viewport_y,
|
||||||
|
viewport_width, viewport_height,
|
||||||
|
&out_x, &out_y,
|
||||||
|
&out_width, &out_height);
|
||||||
|
|
||||||
|
glViewport(out_x, out_y, out_width, out_height);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, saved_framebuffer);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, pass[i].fbo);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, saved_framebuffer);
|
||||||
|
glBlitFramebuffer(0, 0, pass[i].width, pass[i].height, out_x,
|
||||||
|
out_height + out_y, out_x + out_width, out_y,
|
||||||
|
GL_COLOR_BUFFER_BIT,
|
||||||
|
Settings.BilinearFilter ? GL_LINEAR : GL_NEAREST);
|
||||||
|
}
|
||||||
|
// reset vertex attribs set in set_shader_vars
|
||||||
if (using_slang)
|
if (using_slang)
|
||||||
slang_clear_shader_vars();
|
slang_clear_shader_vars();
|
||||||
else
|
else
|
||||||
|
@ -876,12 +915,12 @@ void GLSLShader::register_uniforms()
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLSLShader::set_shader_vars(unsigned int p)
|
void GLSLShader::set_shader_vars(unsigned int p, bool inverted)
|
||||||
{
|
{
|
||||||
unsigned int texunit = 0;
|
unsigned int texunit = 0;
|
||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
|
|
||||||
if (p == pass.size() - 1)
|
if (inverted)
|
||||||
offset = 8;
|
offset = 8;
|
||||||
GLSLUniforms *u = &pass[p].unif;
|
GLSLUniforms *u = &pass[p].unif;
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,7 @@ typedef struct
|
||||||
std::vector<SlangUniform> uniforms;
|
std::vector<SlangUniform> uniforms;
|
||||||
std::vector<uint8_t> ubo_buffer;
|
std::vector<uint8_t> ubo_buffer;
|
||||||
GLuint ubo;
|
GLuint ubo;
|
||||||
|
bool uses_feedback = false;
|
||||||
GLuint feedback_texture;
|
GLuint feedback_texture;
|
||||||
#endif
|
#endif
|
||||||
} GLSLPass;
|
} GLSLPass;
|
||||||
|
@ -159,7 +160,7 @@ typedef struct
|
||||||
void render(GLuint &orig, int width, int height, int viewport_x,
|
void render(GLuint &orig, int width, int height, int viewport_x,
|
||||||
int viewport_y, int viewport_width, int viewport_height,
|
int viewport_y, int viewport_width, int viewport_height,
|
||||||
GLSLViewportCallback vpcallback);
|
GLSLViewportCallback vpcallback);
|
||||||
void set_shader_vars(unsigned int pass);
|
void set_shader_vars(unsigned int pass, bool inverted);
|
||||||
void clear_shader_vars();
|
void clear_shader_vars();
|
||||||
void strip_parameter_pragmas(std::vector<std::string> &lines);
|
void strip_parameter_pragmas(std::vector<std::string> &lines);
|
||||||
GLuint compile_shader(std::vector<std::string> &lines, const char *aliases,
|
GLuint compile_shader(std::vector<std::string> &lines, const char *aliases,
|
||||||
|
@ -189,7 +190,7 @@ typedef struct
|
||||||
void slang_parse_pragmas(std::vector<std::string> &lines, int p);
|
void slang_parse_pragmas(std::vector<std::string> &lines, int p);
|
||||||
GLint slang_compile(std::vector<std::string> &lines, std::string stage);
|
GLint slang_compile(std::vector<std::string> &lines, std::string stage);
|
||||||
void slang_introspect();
|
void slang_introspect();
|
||||||
void slang_set_shader_vars(int p);
|
void slang_set_shader_vars(int p, bool inverted);
|
||||||
void slang_clear_shader_vars();
|
void slang_clear_shader_vars();
|
||||||
|
|
||||||
bool using_feedback = false;
|
bool using_feedback = false;
|
||||||
|
|
|
@ -494,10 +494,14 @@ void GLSLShader::slang_introspect()
|
||||||
}
|
}
|
||||||
else if (indexedtexorsize("PassFeedback", SL_FEEDBACK))
|
else if (indexedtexorsize("PassFeedback", SL_FEEDBACK))
|
||||||
{
|
{
|
||||||
using_feedback = true;
|
|
||||||
u.num++;
|
u.num++;
|
||||||
if (u.type == SL_FEEDBACK + 1)
|
if (u.type == SL_FEEDBACK + 1)
|
||||||
u.type = SL_PASSSIZE;
|
u.type = SL_PASSSIZE;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pass[u.num].uses_feedback = true;
|
||||||
|
using_feedback = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (indexedtexorsize("User", SL_LUTTEXTURE))
|
else if (indexedtexorsize("User", SL_LUTTEXTURE))
|
||||||
{
|
{
|
||||||
|
@ -587,6 +591,11 @@ void GLSLShader::slang_introspect()
|
||||||
p.ubo_buffer.resize(uniform_block_size);
|
p.ubo_buffer.resize(uniform_block_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (using_feedback)
|
||||||
|
for (int i = 1; i < (int)pass.size(); i++)
|
||||||
|
if (pass[i].uses_feedback)
|
||||||
|
glGenTextures(1, &pass[i].feedback_texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const GLfloat coords[] = { 0.0f, 0.0f, 0.0f, 1.0f, // Vertex Positions
|
static const GLfloat coords[] = { 0.0f, 0.0f, 0.0f, 1.0f, // Vertex Positions
|
||||||
|
@ -614,7 +623,7 @@ void GLSLShader::slang_clear_shader_vars()
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLSLShader::slang_set_shader_vars(int p)
|
void GLSLShader::slang_set_shader_vars(int p, bool inverted)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 32, coords, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 32, coords, GL_STATIC_DRAW);
|
||||||
|
@ -631,7 +640,7 @@ void GLSLShader::slang_set_shader_vars(int p)
|
||||||
{
|
{
|
||||||
GLfloat *offset = 0;
|
GLfloat *offset = 0;
|
||||||
offset += 16;
|
offset += 16;
|
||||||
if (p == (int)pass.size() - 1)
|
if (inverted)
|
||||||
offset += 8;
|
offset += 8;
|
||||||
|
|
||||||
glEnableVertexAttribArray(attr);
|
glEnableVertexAttribArray(attr);
|
||||||
|
@ -738,9 +747,6 @@ void GLSLShader::slang_set_shader_vars(int p)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (using_feedback)
|
|
||||||
for (int i = 1; i < (int)pass.size(); i++)
|
|
||||||
glGenTextures(1, &pass[i].feedback_texture);
|
|
||||||
|
|
||||||
if (pass[p].ubo_buffer.size() > 0)
|
if (pass[p].ubo_buffer.size() > 0)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue