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,
|
||||
-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"))
|
||||
{
|
||||
|
@ -33,10 +33,8 @@ static int scale_string_to_enum(const char *string, bool last)
|
|||
{
|
||||
return GLSL_ABSOLUTE;
|
||||
}
|
||||
else if (last)
|
||||
return GLSL_VIEWPORT;
|
||||
else
|
||||
return GLSL_SOURCE;
|
||||
return GLSL_NONE;
|
||||
}
|
||||
|
||||
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:
|
||||
return "absolute";
|
||||
default:
|
||||
return "source";
|
||||
return "undefined";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,15 +150,15 @@ bool GLSLShader::load_shader_preset_file(char *filename)
|
|||
{
|
||||
sprintf(key, "::scale_type_x%u", i);
|
||||
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);
|
||||
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
|
||||
{
|
||||
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_y = scale_type;
|
||||
}
|
||||
|
@ -598,12 +596,17 @@ void GLSLShader::render(GLuint &orig,
|
|||
pass[0].width = width;
|
||||
pass[0].height = height;
|
||||
|
||||
for (int i = 1; i < (int)pass.size(); i++)
|
||||
{
|
||||
GLuint tmp = pass[i].texture;
|
||||
pass[i].texture = pass[i].feedback_texture;
|
||||
pass[i].feedback_texture = tmp;
|
||||
}
|
||||
#ifdef USE_SLANG
|
||||
if (using_slang && using_feedback)
|
||||
for (int i = 1; i < (int)pass.size(); i++)
|
||||
{
|
||||
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
|
||||
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;
|
||||
break;
|
||||
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)
|
||||
|
@ -640,7 +646,15 @@ void GLSLShader::render(GLuint &orig,
|
|||
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
|
||||
glBindTexture(GL_TEXTURE_2D, pass[i].texture);
|
||||
|
@ -720,17 +734,42 @@ void GLSLShader::render(GLuint &orig,
|
|||
glUseProgram(pass[i].program);
|
||||
#ifdef USE_SLANG
|
||||
if (using_slang)
|
||||
slang_set_shader_vars(i);
|
||||
slang_set_shader_vars(i, lastpass && direct_lastpass);
|
||||
else
|
||||
#endif
|
||||
set_shader_vars(i);
|
||||
set_shader_vars(i, lastpass && direct_lastpass);
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
// reset vertex attribs set in set_shader_vars
|
||||
#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)
|
||||
slang_clear_shader_vars();
|
||||
else
|
||||
|
@ -876,12 +915,12 @@ void GLSLShader::register_uniforms()
|
|||
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 offset = 0;
|
||||
|
||||
if (p == pass.size() - 1)
|
||||
if (inverted)
|
||||
offset = 8;
|
||||
GLSLUniforms *u = &pass[p].unif;
|
||||
|
||||
|
|
|
@ -125,6 +125,7 @@ typedef struct
|
|||
std::vector<SlangUniform> uniforms;
|
||||
std::vector<uint8_t> ubo_buffer;
|
||||
GLuint ubo;
|
||||
bool uses_feedback = false;
|
||||
GLuint feedback_texture;
|
||||
#endif
|
||||
} GLSLPass;
|
||||
|
@ -159,7 +160,7 @@ typedef struct
|
|||
void render(GLuint &orig, int width, int height, int viewport_x,
|
||||
int viewport_y, int viewport_width, int viewport_height,
|
||||
GLSLViewportCallback vpcallback);
|
||||
void set_shader_vars(unsigned int pass);
|
||||
void set_shader_vars(unsigned int pass, bool inverted);
|
||||
void clear_shader_vars();
|
||||
void strip_parameter_pragmas(std::vector<std::string> &lines);
|
||||
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);
|
||||
GLint slang_compile(std::vector<std::string> &lines, std::string stage);
|
||||
void slang_introspect();
|
||||
void slang_set_shader_vars(int p);
|
||||
void slang_set_shader_vars(int p, bool inverted);
|
||||
void slang_clear_shader_vars();
|
||||
|
||||
bool using_feedback = false;
|
||||
|
|
|
@ -494,10 +494,14 @@ void GLSLShader::slang_introspect()
|
|||
}
|
||||
else if (indexedtexorsize("PassFeedback", SL_FEEDBACK))
|
||||
{
|
||||
using_feedback = true;
|
||||
u.num++;
|
||||
if (u.type == SL_FEEDBACK + 1)
|
||||
u.type = SL_PASSSIZE;
|
||||
else
|
||||
{
|
||||
pass[u.num].uses_feedback = true;
|
||||
using_feedback = true;
|
||||
}
|
||||
}
|
||||
else if (indexedtexorsize("User", SL_LUTTEXTURE))
|
||||
{
|
||||
|
@ -587,6 +591,11 @@ void GLSLShader::slang_introspect()
|
|||
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
|
||||
|
@ -614,7 +623,7 @@ void GLSLShader::slang_clear_shader_vars()
|
|||
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);
|
||||
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;
|
||||
offset += 16;
|
||||
if (p == (int)pass.size() - 1)
|
||||
if (inverted)
|
||||
offset += 8;
|
||||
|
||||
glEnableVertexAttribArray(attr);
|
||||
|
@ -738,9 +747,6 @@ void GLSLShader::slang_set_shader_vars(int p)
|
|||
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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue