datadir = @datadir@
top_builddir = @top_builddir@
with_demo_app = @with_demo_app@
+with_SDL2 = @with_SDL2@
with_coverage = @with_coverage@
CC=@CC@
CXX=@CXX@
-CXXFLAGS=-Wall @CXXFLAGS@ -I$(GTEST_DIR)/include @Eigen3_CFLAGS@ @GLEW_CFLAGS@ @FFTW3_CFLAGS@
+CXXFLAGS=-Wall @CXXFLAGS@ -I$(GTEST_DIR)/include @SDL2_CFLAGS@ @SDL_CFLAGS@ @Eigen3_CFLAGS@ @epoxy_CFLAGS@ @FFTW3_CFLAGS@
+ifeq ($(with_SDL2),yes)
+CXXFLAGS += -DHAVE_SDL2
+endif
LDFLAGS=@LDFLAGS@
-LDLIBS=@GLEW_LIBS@ @FFTW3_LIBS@ -lpthread
-TEST_LDLIBS=@GLEW_LIBS@ @SDL_LIBS@ -lpthread
-DEMO_LDLIBS=@SDL_image_LIBS@ -lrt -lpthread @libpng_LIBS@ @FFTW3_LIBS@
+LDLIBS=@epoxy_LIBS@ @FFTW3_LIBS@ -lpthread
+TEST_LDLIBS=@epoxy_LIBS@ @SDL2_LIBS@ @SDL_LIBS@ -lpthread
+DEMO_LDLIBS=@SDL2_image_LIBS@ @SDL_image_LIBS@ -lrt -lpthread @libpng_LIBS@ @FFTW3_LIBS@
SHELL=@SHELL@
LIBTOOL=@LIBTOOL@ --tag=CXX
RANLIB=ranlib
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
works fine on Linux and OS X, and Movit is not very POSIX-bound.)
* GNU Make.
* A GPU capable of running GLSL fragment shaders,
- process floating-point textures, and a few other things. If your machine
- is less than five years old _and you have the appropriate drivers_,
- you're home free.
+ processing floating-point textures, and a few other things (all are
+ part of OpenGL 3.0 or newer, although most OpenGL 2.0 cards also
+ have what's needed through extensions). If your machine is less than five
+ years old _and you have the appropriate drivers_, you're home free.
+ GLES3 (for mobile devices) will also work.
* The [Eigen 3], [FFTW3] and [Google Test] libraries. (The library itself
does not depend on the latter, but you probably want to run the unit tests.)
-* The [GLEW] library, for dealing with OpenGL extensions on various
+* The [epoxy] library, for dealing with OpenGL extensions on various
platforms.
Movit has been tested with Intel GPUs with the Mesa drivers
TL;DR, but I am interested in a programming example instead
===========================================================
-Assuming you have an OpenGL context already set up:
+Assuming you have an OpenGL context already set up (either a classic OpenGL
+context, a GL 3.x forward-compatible or core context, or a GLES3 context):
<code>
using namespace movit;
// Unit tests for AlphaDivisionEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "gtest/gtest.h"
#include "image_format.h"
#include "test_util.h"
// Unit tests for AlphaMultiplicationEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "effect_chain.h"
#include "gtest/gtest.h"
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <math.h>
#include <algorithm>
// which is what the user is intended to use, instantiates two copies of
// SingleBlurPassEffect behind the scenes).
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <stddef.h>
#include <string>
// Unit tests for BlurEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <math.h>
#include <string.h>
// Unit tests for ColorspaceConversionEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "colorspace_conversion_effect.h"
#include "gtest/gtest.h"
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "complex_modulate_effect.h"
#include "effect_chain.h"
// don't care about the actual FFT result, just that the convolution property
// holds.)
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <string>
#include "effect.h"
// Unit tests for ComplexModulateEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "effect_chain.h"
#include "gtest/gtest.h"
AC_PROG_CC
AC_PROG_CXX
PKG_CHECK_MODULES([Eigen3], [eigen3])
-PKG_CHECK_MODULES([GLEW], [glew])
+PKG_CHECK_MODULES([epoxy], [epoxy])
PKG_CHECK_MODULES([FFTW3], [fftw3])
-# Needed for unit tests and the demo app.
-PKG_CHECK_MODULES([SDL], [sdl])
+# Needed for unit tests and the demo app. We prefer SDL2 if possible,
+# but can also use classic SDL.
+with_SDL2=no
+with_demo_app=yes
+PKG_CHECK_MODULES([SDL2], [sdl2], [with_SDL2=yes], [
+ PKG_CHECK_MODULES([SDL], [sdl])
+])
# These are only needed for the demo app.
-with_demo_app=yes
-PKG_CHECK_MODULES([SDL_image], [SDL_image], [], [with_demo_app=no; AC_MSG_WARN([SDL_image not found, demo program will not be built])])
+if test $with_SDL2 = "yes"; then
+ PKG_CHECK_MODULES([SDL2_image], [SDL2_image], [], [with_demo_app=no; AC_MSG_WARN([SDL2_image not found, demo program will not be built])])
+else
+ PKG_CHECK_MODULES([SDL_image], [SDL_image], [], [with_demo_app=no; AC_MSG_WARN([SDL_image not found, demo program will not be built])])
+fi
PKG_CHECK_MODULES([libpng], [libpng12], [], [with_demo_app=no; AC_MSG_WARN([libpng12 not found, demo program will not be built])])
AC_SUBST([with_demo_app])
+AC_SUBST([with_SDL2])
with_coverage=no
AC_ARG_ENABLE([coverage], [ --enable-coverage build with information needed to compute test coverage], [with_coverage=yes])
#include <Eigen/Dense>
#include <Eigen/Cholesky>
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <math.h>
#include <stdio.h>
//
// Jain, Anil K.: “Fundamentals of Digital Image Processing”, Prentice Hall, 1988.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <Eigen/Dense>
#include <string>
// Unit tests for DeconvolutionSharpenEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <math.h>
#include <stdlib.h>
#define WIDTH 1280
#define HEIGHT 720
-#include <GL/glew.h>
+#include <epoxy/gl.h>
+
+#ifdef HAVE_SDL2
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_events.h>
+#include <SDL2/SDL_image.h>
+#include <SDL2/SDL_keyboard.h>
+#include <SDL2/SDL_mouse.h>
+#include <SDL2/SDL_video.h>
+#else
#include <SDL/SDL.h>
#include <SDL/SDL_error.h>
#include <SDL/SDL_events.h>
#include <SDL/SDL_keysym.h>
#include <SDL/SDL_mouse.h>
#include <SDL/SDL_video.h>
+#endif
+
#include <assert.h>
#include <features.h>
#include <math.h>
rgba_fmt.Gshift = 8;
rgba_fmt.Bshift = 0;
rgba_fmt.Ashift = 24;
-
+
+#ifndef HAVE_SDL2
rgba_fmt.colorkey = 0;
rgba_fmt.alpha = 255;
+#endif
SDL_Surface *converted = SDL_ConvertSurface(img, &rgba_fmt, SDL_SWSURFACE);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+#ifdef HAVE_SDL2
+ SDL_Window *window = SDL_CreateWindow("OpenGL window",
+ SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED,
+ WIDTH, HEIGHT,
+ SDL_WINDOW_OPENGL);
+ SDL_GLContext context = SDL_GL_CreateContext(window);
+ assert(context != NULL);
+#else
SDL_SetVideoMode(WIDTH, HEIGHT, 0, SDL_OPENGL);
SDL_WM_SetCaption("OpenGL window", NULL);
+#endif
CHECK(init_movit(".", MOVIT_DEBUG_ON));
printf("GPU texture subpixel precision: about %.1f bits\n",
draw_saturation_bar(0.75f, blur_radius / 100.0f);
draw_saturation_bar(0.80f, blurred_mix_amount);
+#ifdef HAVE_SDL2
+ SDL_GL_SwapWindow(window);
+#else
SDL_GL_SwapBuffers();
+#endif
check_error();
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
// where we first blur the picture, and then overlay it on the original
// using the original as a matte.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <string>
// Unit tests for DiffusionEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "diffusion_effect.h"
#include "effect_chain.h"
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <stdio.h>
#include <algorithm>
// 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.
// like many LCD monitors do, but it starts to get very hairy, again, for limited gains.)
// The dither is also deterministic across runs.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <string>
#include "effect.h"
// Unit tests for DitherEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <math.h>
#include "effect_chain.h"
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
// effect instance; use the macro PREFIX() around your identifiers to
// automatically prepend that prefix.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <stddef.h>
#include <map>
#define GL_GLEXT_PROTOTYPES 1
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <locale.h>
#include <math.h>
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
// the EffectChain holds textures and other OpenGL objects that are tied to the
// context.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <stdio.h>
#include <map>
#include <set>
//
// Note that this also contains the tests for some of the simpler effects.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include "effect.h"
TEST(EffectChainTest, RewritingWorksAndTexturesAreAskedForsRGB) {
unsigned char data[] = {
- 0, 64,
- 128, 255,
+ 0, 0, 0, 255,
+ 64, 64, 64, 255,
+ 128, 128, 128, 255,
+ 255, 255, 255, 255,
};
- float expected_data[4] = {
- 1.0f, 0.9771f,
- 0.8983f, 0.0f,
+ float expected_data[] = {
+ 1.0000f, 1.0000f, 1.0000f, 1.0000f,
+ 0.9771f, 0.9771f, 0.9771f, 1.0000f,
+ 0.8983f, 0.8983f, 0.8983f, 1.0000f,
+ 0.0000f, 0.0000f, 0.0000f, 1.0000f
};
- float out_data[4];
- EffectChainTester tester(NULL, 2, 2);
- tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_sRGB);
+ float out_data[4 * 4];
+ EffectChainTester tester(NULL, 1, 4);
+ tester.add_input(data, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_sRGB);
RewritingEffect<InvertEffect> *effect = new RewritingEffect<InvertEffect>();
tester.get_chain()->add_effect(effect);
- tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
+ tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
Node *node = effect->replaced_node;
ASSERT_EQ(1, node->incoming_links.size());
EXPECT_EQ("FlatInput", node->incoming_links[0]->effect->effect_type_id());
EXPECT_EQ("GammaCompressionEffect", node->outgoing_links[0]->effect->effect_type_id());
- expect_equal(expected_data, out_data, 2, 2);
+ expect_equal(expected_data, out_data, 4, 4);
}
TEST(EffectChainTest, RewritingWorksAndColorspaceConversionsAreInserted) {
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <Eigen/Core>
#include <stddef.h>
#include <string>
// Utilities that are often useful for implementing Effect instances,
// but don't need to be included from effect.h.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <stddef.h>
#include <Eigen/Core>
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <string.h>
#include "complex_modulate_effect.h"
// time, which in turn means you cannot change image or kernel size on the fly.
#include <assert.h>
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <string>
#include "effect.h"
// Unit tests for FFTConvolutionEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <math.h>
#include "effect_chain.h"
#include <string.h>
#include <assert.h>
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <fftw3.h>
#include "effect_util.h"
string FFTInput::output_fragment_shader()
{
- return read_file("flat_input.frag");
+ return string("#define FIXUP_SWAP_RB 0\n#define FIXUP_RED_TO_GRAYSCALE 0\n") +
+ read_file("flat_input.frag");
}
void FFTInput::invalidate_pixel_data()
//
// This class is tested as part of by FFTConvolutionEffectTest.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <string>
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <math.h>
#include "effect_chain.h"
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
// scaling), and as fp16 has quite limited range at times, this can be relevant
// on some GPUs for larger sizes.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <string.h>
+#include <epoxy/gl.h>
+#include <gtest/gtest.h>
#include "effect_chain.h"
#include "fft_pass_effect.h"
-#include "glew.h"
-#include "gtest/gtest.h"
#include "image_format.h"
#include "multiply_effect.h"
#include "test_util.h"
#include <string.h>
#include <assert.h>
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "effect_util.h"
#include "flat_input.h"
namespace movit {
-FlatInput::FlatInput(ImageFormat image_format, MovitPixelFormat pixel_format, GLenum type, unsigned width, unsigned height)
+FlatInput::FlatInput(ImageFormat image_format, MovitPixelFormat pixel_format_in, GLenum type, unsigned width, unsigned height)
: image_format(image_format),
- pixel_format(pixel_format),
type(type),
pbo(0),
texture_num(0),
width(width),
height(height),
pitch(width),
- pixel_data(NULL)
+ pixel_data(NULL),
+ fixup_swap_rb(false),
+ fixup_red_to_grayscale(false)
{
assert(type == GL_FLOAT || type == GL_HALF_FLOAT || type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_BYTE);
register_int("output_linear_gamma", &output_linear_gamma);
register_int("needs_mipmaps", &needs_mipmaps);
+
+ // Some types are not supported in all GL versions (e.g. GLES),
+ // and will corrected into the right format in the shader.
+ switch (pixel_format_in) {
+ case FORMAT_BGRA_PREMULTIPLIED_ALPHA:
+ pixel_format = FORMAT_RGBA_PREMULTIPLIED_ALPHA;
+ fixup_swap_rb = true;
+ break;
+ case FORMAT_BGRA_POSTMULTIPLIED_ALPHA:
+ pixel_format = FORMAT_RGBA_POSTMULTIPLIED_ALPHA;
+ fixup_swap_rb = true;
+ break;
+ case FORMAT_BGR:
+ pixel_format = FORMAT_RGB;
+ fixup_swap_rb = true;
+ break;
+ case FORMAT_GRAYSCALE:
+ pixel_format = FORMAT_R;
+ fixup_red_to_grayscale = true;
+ break;
+ default:
+ pixel_format = pixel_format_in;
+ break;
+ }
}
FlatInput::~FlatInput()
internal_format = GL_R32F;
} else if (pixel_format == FORMAT_RG) {
internal_format = GL_RG32F;
+ } else if (pixel_format == FORMAT_RGB) {
+ internal_format = GL_RGB32F;
} else {
internal_format = GL_RGBA32F;
}
internal_format = GL_R16F;
} else if (pixel_format == FORMAT_RG) {
internal_format = GL_RG16F;
+ } else if (pixel_format == FORMAT_RGB) {
+ internal_format = GL_RGB16F;
} else {
internal_format = GL_RGBA16F;
}
internal_format = GL_R16;
} else if (pixel_format == FORMAT_RG) {
internal_format = GL_RG16;
+ } else if (pixel_format == FORMAT_RGB) {
+ internal_format = GL_RGB16;
} else {
internal_format = GL_RGBA16;
}
} else if (output_linear_gamma) {
assert(type == GL_UNSIGNED_BYTE);
- internal_format = GL_SRGB8_ALPHA8;
+ if (pixel_format == FORMAT_RGB) {
+ internal_format = GL_SRGB8;
+ } else if (pixel_format == FORMAT_RGBA_POSTMULTIPLIED_ALPHA) {
+ internal_format = GL_SRGB8_ALPHA8;
+ } else {
+ assert(false);
+ }
} else {
assert(type == GL_UNSIGNED_BYTE);
if (pixel_format == FORMAT_R) {
internal_format = GL_R8;
} else if (pixel_format == FORMAT_RG) {
internal_format = GL_RG8;
+ } else if (pixel_format == FORMAT_RGB) {
+ internal_format = GL_RGB8;
} else {
internal_format = GL_RGBA8;
}
} else if (pixel_format == FORMAT_RGBA_PREMULTIPLIED_ALPHA ||
pixel_format == FORMAT_RGBA_POSTMULTIPLIED_ALPHA) {
format = GL_RGBA;
- } else if (pixel_format == FORMAT_BGR) {
- format = GL_BGR;
- } else if (pixel_format == FORMAT_BGRA_PREMULTIPLIED_ALPHA ||
- pixel_format == FORMAT_BGRA_POSTMULTIPLIED_ALPHA) {
- format = GL_BGRA;
- } else if (pixel_format == FORMAT_GRAYSCALE) {
- format = GL_LUMINANCE;
} else if (pixel_format == FORMAT_RG) {
format = GL_RG;
+ } else if (pixel_format == FORMAT_R) {
+ format = GL_RED;
} else {
assert(false);
}
string FlatInput::output_fragment_shader()
{
- return read_file("flat_input.frag");
+ char buf[256];
+ sprintf(buf, "#define FIXUP_SWAP_RB %d\n#define FIXUP_RED_TO_GRAYSCALE %d\n",
+ fixup_swap_rb, fixup_red_to_grayscale);
+ return buf + read_file("flat_input.frag");
}
void FlatInput::invalidate_pixel_data()
// we flip the y coordinate.
tc.y = 1.0 - tc.y;
- return 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
+ pixel.rb = pixel.br;
+#endif
+#if FIXUP_RED_TO_GRAYSCALE
+ pixel.gb = pixel.rr;
+#endif
+ return pixel;
}
+
+#undef FIXUP_SWAP_RB
+#undef FIXUP_RED_TO_GRAYSCALE
#ifndef _MOVIT_FLAT_INPUT_H
#define _MOVIT_FLAT_INPUT_H 1
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <string>
virtual std::string effect_type_id() const { return "FlatInput"; }
virtual bool can_output_linear_gamma() const {
+ // On desktop OpenGL, there's also GL_SLUMINANCE8 which could give us
+ // support for single-channel sRGB decoding, but it's not supported
+ // on GLES, and we're already actively rewriting single-channel inputs
+ // to GL_RED (even on desktop), so we stick to 3- and 4-channel inputs.
return (movit_srgb_textures_supported &&
type == GL_UNSIGNED_BYTE &&
+ (pixel_format == FORMAT_RGB ||
+ pixel_format == FORMAT_RGBA_POSTMULTIPLIED_ALPHA) &&
(image_format.gamma_curve == GAMMA_LINEAR ||
image_format.gamma_curve == GAMMA_sRGB));
}
virtual AlphaHandling alpha_handling() const {
switch (pixel_format) {
case FORMAT_RGBA_PREMULTIPLIED_ALPHA:
- case FORMAT_BGRA_PREMULTIPLIED_ALPHA:
return INPUT_AND_OUTPUT_PREMULTIPLIED_ALPHA;
case FORMAT_RGBA_POSTMULTIPLIED_ALPHA:
- case FORMAT_BGRA_POSTMULTIPLIED_ALPHA:
return OUTPUT_POSTMULTIPLIED_ALPHA;
+ case FORMAT_R:
case FORMAT_RG:
case FORMAT_RGB:
- case FORMAT_BGR:
- case FORMAT_GRAYSCALE:
return OUTPUT_BLANK_ALPHA;
default:
assert(false);
unsigned width, height, pitch;
const void *pixel_data;
ResourcePool *resource_pool;
+ bool fixup_swap_rb, fixup_red_to_grayscale;
};
} // namespace movit
// Unit tests for FlatInput.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <stddef.h>
#include "effect_chain.h"
--- /dev/null
+out vec4 FragColor;
+
+void main()
+{
+ FragColor = INPUT(tc);
+}
--- /dev/null
+out vec4 FragColor;
+
+void main()
+{
+ FragColor = INPUT(tc);
+}
// Note that Movit's internal formats generally do not have enough accuracy
// for 12-bit input or output.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <string>
#include "effect.h"
// However, the accuracy tests are somewhat simpler, since we
// only need to care about absolute errors and not relative.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <math.h>
#include "gtest/gtest.h"
// Note that Movit's internal formats generally do not have enough accuracy
// for 12-bit input or output.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <string>
#include "effect.h"
// Unit tests for GammaExpansionEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <math.h>
#include "gamma_expansion_effect.h"
// Glow: Cut out the highlights of the image (everything above a certain threshold),
// blur them, and overlay them onto the original image.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <string>
// Unit tests for GlowEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <math.h>
#include "effect_chain.h"
#define GTEST_HAS_EXCEPTIONS 0
+#ifdef HAVE_SDL2
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_video.h>
+#else
#include <SDL/SDL.h>
#include <SDL/SDL_error.h>
#include <SDL/SDL_video.h>
+#endif
#include <stdio.h>
#include <stdlib.h>
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+#ifdef HAVE_SDL2
+ // You can uncomment this if you want to try a core context.
+ // For Mesa, you can get the same effect by doing
+ //
+ // export MESA_GL_VERSION_OVERRIDE=3.1FC
+ //
+ // before running tests.
+// SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+// SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+// SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
+ SDL_Window *window = SDL_CreateWindow("OpenGL window for unit test",
+ SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED,
+ 32, 32,
+ SDL_WINDOW_OPENGL);
+ SDL_GLContext context = SDL_GL_CreateContext(window);
+ assert(context != NULL);
+#else
SDL_SetVideoMode(32, 32, 0, SDL_OPENGL);
SDL_WM_SetCaption("OpenGL window for unit test", NULL);
+#endif
testing::InitGoogleTest(&argc, argv);
int err = RUN_ALL_TESTS();
--- /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);
+}
+#ifdef GL_ES
+precision highp float;
+#endif
+
#ifdef GL_EXT_gpu_shader4
// We sometimes want round().
#extension GL_EXT_gpu_shader4 : enable
#endif
varying vec2 tc;
+
+vec4 tex2D(sampler2D s, vec2 coord)
+{
+ return texture2D(s, coord);
+}
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <stddef.h>
#include <algorithm>
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.
// Now read the data back and see what the card did.
// (We only look at the red channel; the others will surely be the same.)
// We assume a linear ramp; anything else will give sort of odd results here.
- float out_data[width];
- glReadPixels(0, 0, width, 1, GL_RED, GL_FLOAT, out_data);
+ float out_data[width * 4];
+ glReadPixels(0, 0, width, 1, GL_RGBA, GL_FLOAT, out_data);
check_error();
float biggest_jump = 0.0f;
for (unsigned i = 1; i < width; ++i) {
- assert(out_data[i] >= out_data[i - 1]);
- biggest_jump = max(biggest_jump, out_data[i] - out_data[i - 1]);
+ assert(out_data[i * 4] >= out_data[(i - 1) * 4]);
+ biggest_jump = max(biggest_jump, out_data[i * 4] - out_data[(i - 1) * 4]);
}
assert(biggest_jump > 0.0);
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.
// Now read the data back and see what the card did. (Ignore the last value.)
// (We only look at the red channel; the others will surely be the same.)
- unsigned char out_data[512];
- glReadPixels(0, 0, 512, 1, GL_RED, GL_UNSIGNED_BYTE, out_data);
+ unsigned char out_data[512 * 4];
+ glReadPixels(0, 0, 512, 1, GL_RGBA, GL_UNSIGNED_BYTE, out_data);
check_error();
int wrongly_rounded = 0;
for (unsigned i = 0; i < 255; ++i) {
- if (out_data[i * 2 + 0] != i) {
+ if (out_data[(i * 2 + 0) * 4] != i) {
++wrongly_rounded;
}
- if (out_data[i * 2 + 1] != i + 1) {
+ if (out_data[(i * 2 + 1) * 4] != i + 1) {
++wrongly_rounded;
}
}
bool check_extensions()
{
+ // GLES generally doesn't use extensions as actively as desktop OpenGL.
+ // For now, we say that for GLES, we require GLES 3, which has everything
+ // we need.
+ //
+ // Since we use implicit #version 100, we don't have round(). We will
+ // fix this at some later stage.
+ if (!epoxy_is_desktop_gl()) {
+ if (epoxy_gl_version() >= 30) {
+ movit_srgb_textures_supported = true;
+ movit_shader_rounding_supported = false;
+ } else {
+ return false;
+ }
+ }
+
// We fundamentally need FBOs and floating-point textures.
- if (!glewIsSupported("GL_ARB_framebuffer_object")) return false;
- if (!glewIsSupported("GL_ARB_texture_float")) return false;
+ // FBOs are covered by OpenGL 1.5, and are not an extension there.
+ // Floating-point textures are part of OpenGL 3.0 and newer.
+ if (epoxy_gl_version() < 15 &&
+ !epoxy_has_gl_extension("GL_ARB_framebuffer_object")) return false;
+ if (epoxy_gl_version() < 30 &&
+ !epoxy_has_gl_extension("GL_ARB_texture_float")) return false;
// We assume that we can use non-power-of-two textures without restrictions.
- if (!glewIsSupported("GL_ARB_texture_non_power_of_two")) return false;
+ if (epoxy_gl_version() < 20 &&
+ !epoxy_has_gl_extension("GL_ARB_texture_non_power_of_two")) return false;
// We also need GLSL fragment shaders.
- if (!glewIsSupported("GL_ARB_fragment_shader")) return false;
- if (!glewIsSupported("GL_ARB_shading_language_100")) return false;
+ if (epoxy_gl_version() < 20) {
+ if (!epoxy_has_gl_extension("GL_ARB_fragment_shader")) return false;
+ if (!epoxy_has_gl_extension("GL_ARB_shading_language_100")) return false;
+ }
// FlatInput and YCbCrInput uses PBOs. (They could in theory do without,
// but no modern card would really not provide it.)
- if (!glewIsSupported("GL_ARB_pixel_buffer_object")) return false;
+ if (epoxy_gl_version() < 21 &&
+ !epoxy_has_gl_extension("GL_ARB_pixel_buffer_object")) return false;
// ResampleEffect uses RG textures to encode a two-component LUT.
- if (!glewIsSupported("GL_ARB_texture_rg")) return false;
+ if (epoxy_gl_version() < 30 &&
+ !epoxy_has_gl_extension("GL_ARB_texture_rg")) return false;
// sRGB texture decode would be nice, but are not mandatory
// (GammaExpansionEffect can do the same thing if needed).
- movit_srgb_textures_supported = glewIsSupported("GL_EXT_texture_sRGB");
+ movit_srgb_textures_supported =
+ (epoxy_gl_version() >= 21 || epoxy_has_gl_extension("GL_EXT_texture_sRGB"));
// We may want to use round() at the end of the final shader,
// if supported. We need either GLSL 1.30 or this extension to do that,
// and 1.30 brings with it other things that we don't want to demand
// for now.
- movit_shader_rounding_supported = glewIsSupported("GL_EXT_gpu_shader4");
+ movit_shader_rounding_supported =
+ (epoxy_gl_version() >= 30 || epoxy_has_gl_extension("GL_EXT_gpu_shader4"));
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)
movit_data_directory = new string(data_directory);
movit_debug_level = debug_level;
- GLenum err = glewInit();
- if (err != GLEW_OK) {
- return false;
- }
-
// geez
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
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)
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <math.h>
#include "effect_util.h"
// Also, gamma is a case where we would not want premultiplied alpha.
// Thus, we have to divide away alpha first, and then re-multiply it back later.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <string>
#include "effect.h"
// Unit tests for LiftGammaGainEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "effect_chain.h"
#include "gtest/gtest.h"
// Unit tests for LumaMixEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "effect_chain.h"
#include "gtest/gtest.h"
// Unit tests for MixEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "effect_chain.h"
#include "gtest/gtest.h"
Requires:
Conflicts:
Libs: -lmovit
-Libs.private: @GLEW_LIBS@ @FFTW3_LIBS@
-Cflags: -I${includedir}/movit @Eigen3_CFLAGS@ @GLEW_CFLAGS@ @FFTW3_CFLAGS@
+Libs.private: @epoxy_LIBS@ @FFTW3_LIBS@
+Cflags: -I${includedir}/movit @Eigen3_CFLAGS@ @epoxy_CFLAGS@ @FFTW3_CFLAGS@
// sending it through OverlayEffect, e.g. with R=G=B=A=0.3 to get 30% alpha
// (remember, alpha is premultiplied).
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <string>
#include "effect.h"
// Unit tests for OverlayEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "effect_chain.h"
#include "gtest/gtest.h"
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include "effect_util.h"
// You may not change it after calling finalize(), since that could change the
// graph (need_linear_light() etc. depend on the border color you choose).
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <string>
#include "effect.h"
// Unit tests for AlphaMultiplicationEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <stddef.h>
#include "effect_chain.h"
// Three-lobed Lanczos, the most common choice.
#define LANCZOS_RADIUS 3.0
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <limits.h>
#include <math.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);
// which is what the user is intended to use, instantiates two copies of
// SingleResamplePassEffect behind the scenes).
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <stddef.h>
#include <string>
// Unit tests for ResampleEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
+#include <gtest/gtest.h>
#include <math.h>
#include "effect_chain.h"
#include "flat_input.h"
-#include "glew.h"
-#include "gtest/gtest.h"
#include "image_format.h"
#include "resample_effect.h"
#include "test_util.h"
#include <map>
#include <string>
#include <utility>
+#include <epoxy/gl.h>
-#include "glew.h"
#include "init.h"
#include "resource_pool.h"
#include "util.h"
case GL_SRGB8_ALPHA8:
format = GL_RGBA;
break;
+ case GL_RGB32F:
+ case GL_RGB16F:
+ case GL_RGB8:
+ format = GL_RGB;
+ break;
case GL_RG32F:
case GL_RG16F:
+ case GL_RG8:
format = GL_RG;
break;
+ case GL_R32F:
+ case GL_R16F:
case GL_R8:
format = GL_RED;
break;
assert(false);
}
+ // Same with type; GLES is stricter than desktop OpenGL here.
+ GLenum type;
+ switch (internal_format) {
+ case GL_RGBA32F_ARB:
+ case GL_RGBA16F_ARB:
+ case GL_RGB32F:
+ case GL_RGB16F:
+ case GL_RG32F:
+ case GL_RG16F:
+ case GL_R32F:
+ case GL_R16F:
+ type = GL_FLOAT;
+ break;
+ case GL_SRGB8_ALPHA8:
+ case GL_RGBA8:
+ case GL_RGB8:
+ case GL_RG8:
+ case GL_R8:
+ type = GL_UNSIGNED_BYTE;
+ break;
+ default:
+ // TODO: Add more here as needed.
+ assert(false);
+ }
+
+
GLuint texture_num;
glGenTextures(1, &texture_num);
check_error();
glBindTexture(GL_TEXTURE_2D, texture_num);
check_error();
- glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, type, NULL);
check_error();
glBindTexture(GL_TEXTURE_2D, 0);
check_error();
case GL_RGBA16F_ARB:
bytes_per_pixel = 8;
break;
+ case GL_RGB32F_ARB:
+ bytes_per_pixel = 12;
+ break;
+ case GL_RGB16F_ARB:
+ bytes_per_pixel = 6;
+ break;
case GL_RGBA8:
case GL_SRGB8_ALPHA8:
bytes_per_pixel = 4;
break;
+ case GL_RGB8:
+ case GL_SRGB8:
+ bytes_per_pixel = 3;
+ break;
case GL_RG32F:
bytes_per_pixel = 8;
break;
case GL_RG16F:
bytes_per_pixel = 4;
break;
+ case GL_R32F:
+ bytes_per_pixel = 4;
+ break;
+ case GL_R16F:
+ bytes_per_pixel = 2;
+ break;
case GL_R8:
bytes_per_pixel = 1;
break;
// safely called from multiple threads at the same time, provided they have
// separate (but sharing) OpenGL contexts.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <pthread.h>
#include <stddef.h>
#include <list>
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "sandbox_effect.h"
#include "util.h"
// throwaway code. When you're happy, you can do a bit of search and replace
// to give it a proper name and its own place in the build system.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <string>
#include "effect.h"
// Unit tests for SaturationEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "effect_chain.h"
#include "gtest/gtest.h"
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "effect_chain.h"
#include "slice_effect.h"
// Note that vertical slices happen from the top, consistent with the rest of
// Movit.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <string>
#include "effect.h"
// Unit tests for SliceEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "effect_chain.h"
#include "flat_input.h"
#include <math.h>
#include <stdio.h>
#include <algorithm>
+#include <epoxy/gl.h>
+#include <gtest/gtest.h>
+#include <gtest/gtest-message.h>
#include "flat_input.h"
-#include "glew.h"
-#include "gtest/gtest.h"
-#include "gtest/gtest-message.h"
#include "init.h"
#include "resource_pool.h"
#include "test_util.h"
chain.render_to_fbo(fbo, width, height);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
- glReadPixels(0, 0, width, height, format, GL_FLOAT, out_data);
+ check_error();
+ if (!epoxy_is_desktop_gl() && (format == GL_RED || format == GL_BLUE || format == GL_ALPHA)) {
+ // GLES will only read GL_RGBA.
+ float *temp = new float[width * height * 4];
+ glReadPixels(0, 0, width, height, GL_RGBA, GL_FLOAT, temp);
+ check_error();
+ if (format == GL_ALPHA) {
+ for (unsigned i = 0; i < width * height; ++i) {
+ out_data[i] = temp[i * 4 + 3];
+ }
+ } else if (format == GL_BLUE) {
+ for (unsigned i = 0; i < width * height; ++i) {
+ out_data[i] = temp[i * 4 + 2];
+ }
+ } else {
+ for (unsigned i = 0; i < width * height; ++i) {
+ out_data[i] = temp[i * 4];
+ }
+ }
+ delete[] temp;
+ } else {
+ glReadPixels(0, 0, width, height, format, GL_FLOAT, out_data);
+ check_error();
+ }
if (format == GL_RGBA) {
width *= 4;
chain.render_to_fbo(fbo, width, height);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
- glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, out_data);
+ check_error();
+ if (!epoxy_is_desktop_gl() && (format == GL_RED || format == GL_BLUE || format == GL_ALPHA)) {
+ // GLES will only read GL_RGBA.
+ unsigned char *temp = new unsigned char[width * height * 4];
+ glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, temp);
+ check_error();
+ if (format == GL_ALPHA) {
+ for (unsigned i = 0; i < width * height; ++i) {
+ out_data[i] = temp[i * 4 + 3];
+ }
+ } else if (format == GL_BLUE) {
+ for (unsigned i = 0; i < width * height; ++i) {
+ out_data[i] = temp[i * 4 + 2];
+ }
+ } else {
+ for (unsigned i = 0; i < width * height; ++i) {
+ out_data[i] = temp[i * 4];
+ }
+ }
+ delete[] temp;
+ } else {
+ glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, out_data);
+ check_error();
+ }
if (format == GL_RGBA) {
width *= 4;
#ifndef _MOVIT_TEST_UTIL_H
#define _MOVIT_TEST_UTIL_H 1
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "effect_chain.h"
#include "image_format.h"
--- /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.
+}
+#ifdef GL_ES
+precision highp float;
+#endif
+
uniform sampler2D tex;
varying vec2 tc;
// See DeconvolutionSharpenEffect for a different, possibly better
// sharpening algorithm.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <string>
// Unit tests for UnsharpMaskEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <math.h>
#include "effect_chain.h"
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <math.h>
#include <stdio.h>
#if defined(__DARWIN__)
#include <OpenGL/OpenGL.h>
#elif defined(WIN32)
-#include <GL/wglew.h>
+#include <epoxy/wgl.h>
#else
-#include <GL/glxew.h>
+#include <epoxy/glx.h>
#endif
using namespace std;
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);
// Various utilities.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <stdio.h>
#include <stdlib.h>
#include <Eigen/Core>
// 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);
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <math.h>
// A circular vignette, falling off as cos² of the distance from the center
// (the classic formula for approximating a real lens).
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <string>
#include "effect.h"
// Unit tests for VignetteEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <math.h>
#include "effect_chain.h"
--- /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;
+}
#include <Eigen/Core>
#include <Eigen/LU>
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include "colorspace_conversion_effect.h"
// Color correction in LMS color space.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <string>
#include "effect.h"
// Unit tests for WhiteBalanceEffect.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include "effect_chain.h"
#include "gtest/gtest.h"
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <math.h>
#include "widgets.h"
#include <Eigen/Core>
#include <Eigen/LU>
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
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);
// imprecisely, called “YUV”), which is typically what you get from a video decoder.
// It upsamples planes as needed, using the default linear upsampling OpenGL gives you.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include <string>
// Unit tests for YCbCrInput.
// FIXME: This class really ought to support mipmaps.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <stddef.h>
#include "effect_chain.h"