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 += texture1d.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.
- 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.
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) {
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 += 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
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 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
// 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
--- /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);
+}
#endif
varying vec2 tc;
+
+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;
+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
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.
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.
return true;
}
+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)
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();
// 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)
#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);
--- /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);
}
+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);
// 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);
--- /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;
- 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);