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:
Brandon Wright 2019-01-27 17:43:22 -06:00
parent 58e1bfadfa
commit 8c8805da40
3 changed files with 75 additions and 29 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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)
{ {