We support 1.10 (for OpenGL 2.1 cards), 1.30 (for OpenGL 3.2 core contexts),
and 3.00 ES (for GLES3). There's some code duplication, but thankfully
not a whole lot.
With this, we compile in core contexts without any warning from ATI's driver,
and should also in theory be GLES3 compliant (tested on NVidia's desktop driver).
20 files changed:
HDRS += $(INPUTS:=.h)
HDRS += $(EFFECTS:=.h)
HDRS += $(INPUTS:=.h)
HDRS += $(EFFECTS:=.h)
-SHADERS = vs.vert header.frag footer.frag
+SHADERS = vs.vert vs.130.vert vs.300es.vert
+SHADERS += header.frag header.130.frag header.300es.frag
+SHADERS += footer.frag footer.130.frag footer.300es.frag
+SHADERS += texture1d.frag texture1d.130.frag footer.300es.frag
SHADERS += $(INPUTS:=.frag)
SHADERS += $(EFFECTS:=.frag)
SHADERS += highlight_cutoff_effect.frag
SHADERS += overlay_matte_effect.frag
SHADERS += $(INPUTS:=.frag)
SHADERS += $(EFFECTS:=.frag)
SHADERS += highlight_cutoff_effect.frag
SHADERS += overlay_matte_effect.frag
-SHADERS += texture1d.frag
# These purposefully do not exist.
MISSING_SHADERS = diffusion_effect.frag glow_effect.frag unsharp_mask_effect.frag resize_effect.frag
# These purposefully do not exist.
MISSING_SHADERS = diffusion_effect.frag glow_effect.frag unsharp_mask_effect.frag resize_effect.frag
// and if there's any inaccuracy earlier in the chain so that it becomes e.g.
// 254.8, it's better to just get it rounded off than to dither and have it
// possibly get down to 254. This is not the case for the color components.
// and if there's any inaccuracy earlier in the chain so that it becomes e.g.
// 254.8, it's better to just get it rounded off than to dither and have it
// possibly get down to 254. This is not the case for the color components.
- result.rgb += texture2D(PREFIX(dither_tex), tc * PREFIX(tc_scale)).xxx;
+ result.rgb += tex2D(PREFIX(dither_tex), tc * PREFIX(tc_scale)).xxx;
// NEED_EXPLICIT_ROUND will be #defined to 1 if the GPU has inaccurate
// fp32 -> int8 framebuffer rounding, and 0 otherwise.
// NEED_EXPLICIT_ROUND will be #defined to 1 if the GPU has inaccurate
// fp32 -> int8 framebuffer rounding, and 0 otherwise.
void EffectChain::compile_glsl_program(Phase *phase)
{
void EffectChain::compile_glsl_program(Phase *phase)
{
- string frag_shader = read_file("header.frag");
+ string frag_shader = read_version_dependent_file("header", "frag");
// Create functions for all the texture inputs that we need.
for (unsigned i = 0; i < phase->inputs.size(); ++i) {
// Create functions for all the texture inputs that we need.
for (unsigned i = 0; i < phase->inputs.size(); ++i) {
frag_shader += string("uniform sampler2D tex_") + effect_id + ";\n";
frag_shader += string("vec4 ") + effect_id + "(vec2 tc) {\n";
frag_shader += string("uniform sampler2D tex_") + effect_id + ";\n";
frag_shader += string("vec4 ") + effect_id + "(vec2 tc) {\n";
- frag_shader += "\treturn texture2D(tex_" + string(effect_id) + ", tc);\n";
+ frag_shader += "\treturn tex2D(tex_" + string(effect_id) + ", tc);\n";
frag_shader += "}\n";
frag_shader += "\n";
}
frag_shader += "}\n";
frag_shader += "\n";
}
frag_shader += "\n";
}
frag_shader += string("#define INPUT ") + phase->effect_ids[phase->effects.back()] + "\n";
frag_shader += "\n";
}
frag_shader += string("#define INPUT ") + phase->effect_ids[phase->effects.back()] + "\n";
- frag_shader.append(read_file("footer.frag"));
+ frag_shader.append(read_version_dependent_file("footer", "frag"));
- phase->glsl_program_num = resource_pool->compile_glsl_program(read_file("vs.vert"), frag_shader);
+ string vert_shader = read_version_dependent_file("vs", "vert");
+ phase->glsl_program_num = resource_pool->compile_glsl_program(vert_shader, frag_shader);
// Prepare the geometry for the fullscreen quad used in this phase.
// (We have separate VAOs per shader, since the bindings can in theory
// Prepare the geometry for the fullscreen quad used in this phase.
// (We have separate VAOs per shader, since the bindings can in theory
vec4 FUNCNAME(vec2 tc) {
#if DIRECTION_VERTICAL
vec4 FUNCNAME(vec2 tc) {
#if DIRECTION_VERTICAL
- vec4 support = texture2D(PREFIX(support_tex), vec2(tc.y * PREFIX(num_repeats), 0.0));
+ vec4 support = tex2D(PREFIX(support_tex), vec2(tc.y * PREFIX(num_repeats), 0.0));
vec4 c1 = INPUT(vec2(tc.x, tc.y + support.x));
vec4 c2 = INPUT(vec2(tc.x, tc.y + support.y));
#else
vec4 c1 = INPUT(vec2(tc.x, tc.y + support.x));
vec4 c2 = INPUT(vec2(tc.x, tc.y + support.y));
#else
- vec4 support = texture2D(PREFIX(support_tex), vec2(tc.x * PREFIX(num_repeats), 0.0));
+ vec4 support = tex2D(PREFIX(support_tex), vec2(tc.x * PREFIX(num_repeats), 0.0));
vec4 c1 = INPUT(vec2(tc.x + support.x, tc.y));
vec4 c2 = INPUT(vec2(tc.x + support.y, tc.y));
#endif
vec4 c1 = INPUT(vec2(tc.x + support.x, tc.y));
vec4 c2 = INPUT(vec2(tc.x + support.y, tc.y));
#endif
// we flip the y coordinate.
tc.y = 1.0 - tc.y;
// we flip the y coordinate.
tc.y = 1.0 - tc.y;
- vec4 pixel = texture2D(PREFIX(tex), tc);
+ vec4 pixel = tex2D(PREFIX(tex), tc);
// These two are #defined to 0 or 1 in flat_input.cpp.
#if FIXUP_SWAP_RB
// These two are #defined to 0 or 1 in flat_input.cpp.
#if FIXUP_SWAP_RB
--- /dev/null
+out vec4 FragColor;
+
+void main()
+{
+ FragColor = INPUT(tc);
+}
--- /dev/null
+out vec4 FragColor;
+
+void main()
+{
+ FragColor = INPUT(tc);
+}
--- /dev/null
+#version 130
+
+in vec2 tc;
+
+vec4 tex2D(sampler2D s, vec2 coord)
+{
+ return texture(s, coord);
+}
--- /dev/null
+#version 300 es
+
+precision highp float;
+
+in vec2 tc;
+
+vec4 tex2D(sampler2D s, vec2 coord)
+{
+ return texture(s, coord);
+}
+
+vec4 tex2D(sampler2D s, vec2 coord)
+{
+ return texture2D(s, coord);
+}
bool movit_srgb_textures_supported;
int movit_num_wrongly_rounded;
bool movit_shader_rounding_supported;
bool movit_srgb_textures_supported;
int movit_num_wrongly_rounded;
bool movit_shader_rounding_supported;
+MovitShaderModel movit_shader_model;
// The rules for objects with nontrivial constructors in static scope
// are somewhat convoluted, and easy to mess up. We simply have a
// The rules for objects with nontrivial constructors in static scope
// are somewhat convoluted, and easy to mess up. We simply have a
glViewport(0, 0, width, 1);
GLuint glsl_program_num = resource_pool.compile_glsl_program(
glViewport(0, 0, width, 1);
GLuint glsl_program_num = resource_pool.compile_glsl_program(
- read_file("vs.vert"), read_file("texture1d.frag"));
+ read_version_dependent_file("vs", "vert"),
+ read_version_dependent_file("texture1d", "frag"));
glUseProgram(glsl_program_num);
check_error();
glUniform1i(glGetUniformLocation(glsl_program_num, "tex"), 0); // Bind the 2D sampler.
glUseProgram(glsl_program_num);
check_error();
glUniform1i(glGetUniformLocation(glsl_program_num, "tex"), 0); // Bind the 2D sampler.
glViewport(0, 0, 512, 1);
GLuint glsl_program_num = resource_pool.compile_glsl_program(
glViewport(0, 0, 512, 1);
GLuint glsl_program_num = resource_pool.compile_glsl_program(
- read_file("vs.vert"), read_file("texture1d.frag"));
+ read_version_dependent_file("vs", "vert"),
+ read_version_dependent_file("texture1d", "frag"));
glUseProgram(glsl_program_num);
check_error();
glUniform1i(glGetUniformLocation(glsl_program_num, "tex"), 0); // Bind the 2D sampler.
glUseProgram(glsl_program_num);
check_error();
glUniform1i(glGetUniformLocation(glsl_program_num, "tex"), 0); // Bind the 2D sampler.
+double get_glsl_version()
+{
+ char *glsl_version_str = strdup((const char *)glGetString(GL_SHADING_LANGUAGE_VERSION));
+
+ // Skip past the first period.
+ char *ptr = strchr(glsl_version_str, '.');
+ assert(ptr != NULL);
+ ++ptr;
+
+ // Now cut the string off at the next period or space, whatever comes first
+ // (unless the string ends first).
+ while (*ptr && *ptr != '.' && *ptr != ' ') {
+ ++ptr;
+ }
+ *ptr = '\0';
+
+ // Now we have something on the form X.YY. We convert it to a float, and hope
+ // that if it's inexact (e.g. 1.30), atof() will round the same way the
+ // compiler will.
+ float glsl_version = atof(glsl_version_str);
+ free(glsl_version_str);
+
+ return glsl_version;
+}
+
} // namespace
bool init_movit(const string& data_directory, MovitDebugLevel debug_level)
} // namespace
bool init_movit(const string& data_directory, MovitDebugLevel debug_level)
if (!check_extensions()) {
return false;
}
if (!check_extensions()) {
return false;
}
+
+ // Find out what shader model we should compile for.
+ if (epoxy_is_desktop_gl()) {
+ if (get_glsl_version() >= 1.30) {
+ movit_shader_model = MOVIT_GLSL_130;
+ } else {
+ movit_shader_model = MOVIT_GLSL_110;
+ }
+ } else {
+ movit_shader_model = MOVIT_ESSL_300;
+ }
+
measure_texel_subpixel_precision();
measure_roundoff_problems();
measure_texel_subpixel_precision();
measure_roundoff_problems();
// Whether the GPU in use supports GL_EXT_texture_sRGB.
extern bool movit_srgb_textures_supported;
// Whether the GPU in use supports GL_EXT_texture_sRGB.
extern bool movit_srgb_textures_supported;
+// What shader model we are compiling for. This only affects the choice
+// of a few files (like header.frag); most of the shaders are the same.
+enum MovitShaderModel {
+ MOVIT_GLSL_110,
+ MOVIT_GLSL_130,
+ MOVIT_ESSL_300
+};
+extern MovitShaderModel movit_shader_model;
+
} // namespace movit
#endif // !defined(_MOVIT_INIT_H)
} // namespace movit
#endif // !defined(_MOVIT_INIT_H)
#else
sample_tc.y = tc.x * PREFIX(num_loops);
#endif
#else
sample_tc.y = tc.x * PREFIX(num_loops);
#endif
- vec2 sample = texture2D(PREFIX(sample_tex), sample_tc).rg;
+ vec2 sample = tex2D(PREFIX(sample_tex), sample_tc).rg;
#if DIRECTION_VERTICAL
tc.y = sample.g + floor(sample_tc.y) * PREFIX(slice_height);
#if DIRECTION_VERTICAL
tc.y = sample.g + floor(sample_tc.y) * PREFIX(slice_height);
--- /dev/null
+#version 130
+
+uniform sampler2D tex;
+in vec2 tc;
+
+out vec4 FragColor;
+
+void main()
+{
+ FragColor = texture(tex, tc); // Second component is irrelevant.
+}
--- /dev/null
+#version 300 es
+
+precision highp float;
+
+uniform sampler2D tex;
+in vec2 tc;
+
+out vec4 FragColor;
+
+void main()
+{
+ FragColor = texture(tex, tc); // Second component is irrelevant.
+}
return string(buf, len);
}
return string(buf, len);
}
+string read_version_dependent_file(const string &base, const string &extension)
+{
+ if (movit_shader_model == MOVIT_GLSL_110) {
+ return read_file(base + "." + extension);
+ } else if (movit_shader_model == MOVIT_GLSL_130) {
+ return read_file(base + ".130." + extension);
+ } else if (movit_shader_model == MOVIT_ESSL_300) {
+ return read_file(base + ".300es." + extension);
+ } else {
+ assert(false);
+ }
+}
+
GLuint compile_shader(const string &shader_src, GLenum type)
{
GLuint obj = glCreateShader(type);
GLuint compile_shader(const string &shader_src, GLenum type)
{
GLuint obj = glCreateShader(type);
// Dies if the file does not exist.
std::string read_file(const std::string &filename);
// Dies if the file does not exist.
std::string read_file(const std::string &filename);
+// Reads <base>.<extension>, <base>.130.<extension> or <base>.300es.<extension> and
+// returns its contents, depending on <movit_shader_level>.
+std::string read_version_dependent_file(const std::string &base, const std::string &extension);
+
// Compile the given GLSL shader (typically a vertex or fragment shader)
// and return the object number.
GLuint compile_shader(const std::string &shader_src, GLenum type);
// Compile the given GLSL shader (typically a vertex or fragment shader)
// and return the object number.
GLuint compile_shader(const std::string &shader_src, GLenum type);
--- /dev/null
+#version 130
+
+in vec2 position;
+in vec2 texcoord;
+out vec2 tc;
+
+void main()
+{
+ // The result of glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0) is:
+ //
+ // 2.000 0.000 0.000 -1.000
+ // 0.000 2.000 0.000 -1.000
+ // 0.000 0.000 -2.000 -1.000
+ // 0.000 0.000 0.000 1.000
+ gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, -1.0, 1.0);
+ tc = texcoord;
+}
--- /dev/null
+#version 300 es
+
+precision highp float;
+
+in vec2 position;
+in vec2 texcoord;
+out vec2 tc;
+
+void main()
+{
+ // The result of glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0) is:
+ //
+ // 2.000 0.000 0.000 -1.000
+ // 0.000 2.000 0.000 -1.000
+ // 0.000 0.000 -2.000 -1.000
+ // 0.000 0.000 0.000 1.000
+ gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, -1.0, 1.0);
+ tc = texcoord;
+}
tc.y = 1.0 - tc.y;
vec3 ycbcr;
tc.y = 1.0 - tc.y;
vec3 ycbcr;
- ycbcr.x = texture2D(PREFIX(tex_y), tc).x;
- ycbcr.y = texture2D(PREFIX(tex_cb), tc + PREFIX(cb_offset)).x;
- ycbcr.z = texture2D(PREFIX(tex_cr), tc + PREFIX(cr_offset)).x;
+ ycbcr.x = tex2D(PREFIX(tex_y), tc).x;
+ ycbcr.y = tex2D(PREFIX(tex_cb), tc + PREFIX(cb_offset)).x;
+ ycbcr.z = tex2D(PREFIX(tex_cr), tc + PREFIX(cr_offset)).x;
ycbcr -= PREFIX(offset);
ycbcr *= PREFIX(scale);
ycbcr -= PREFIX(offset);
ycbcr *= PREFIX(scale);