]> git.sesse.net Git - movit/blob - init.cpp
It's now 2014 :-P (Happy new year!)
[movit] / init.cpp
1 #include <GL/glew.h>
2 #include <assert.h>
3 #include <stddef.h>
4 #include <algorithm>
5 #include <string>
6
7 #include "init.h"
8 #include "util.h"
9
10 bool movit_initialized = false;
11 MovitDebugLevel movit_debug_level = MOVIT_DEBUG_ON;
12 float movit_texel_subpixel_precision;
13 bool movit_srgb_textures_supported;
14
15 // The rules for objects with nontrivial constructors in static scope
16 // are somewhat convoluted, and easy to mess up. We simply have a
17 // pointer instead (and never care to clean it up).
18 std::string *movit_data_directory = NULL;
19
20 namespace {
21
22 void measure_texel_subpixel_precision()
23 {
24         static const unsigned width = 4096;
25
26         // Generate a destination texture to render to, and an FBO.
27         GLuint dst_texnum, fbo;
28
29         glGenTextures(1, &dst_texnum);
30         check_error();
31         glBindTexture(GL_TEXTURE_2D, dst_texnum);
32         check_error();
33         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, width, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
34         check_error();
35
36         glGenFramebuffers(1, &fbo);
37         check_error();
38         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
39         check_error();
40         glFramebufferTexture2D(
41                 GL_FRAMEBUFFER,
42                 GL_COLOR_ATTACHMENT0,
43                 GL_TEXTURE_2D,
44                 dst_texnum,
45                 0);
46         check_error();
47
48         // Now generate a simple texture that's just [0,1].
49         GLuint src_texnum;
50         float texdata[] = { 0, 1 };
51         glGenTextures(1, &src_texnum);
52         check_error();
53         glBindTexture(GL_TEXTURE_1D, src_texnum);
54         check_error();
55         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
56         check_error();
57         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
58         check_error();
59         glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE16F_ARB, 2, 0, GL_LUMINANCE, GL_FLOAT, texdata);
60         check_error();
61         glEnable(GL_TEXTURE_1D);
62         check_error();
63
64         // Basic state.
65         glDisable(GL_BLEND);
66         check_error();
67         glDisable(GL_DEPTH_TEST);
68         check_error();
69         glDepthMask(GL_FALSE);
70         check_error();
71
72         glViewport(0, 0, width, 1);
73
74         glMatrixMode(GL_PROJECTION);
75         glLoadIdentity();
76         glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
77
78         glMatrixMode(GL_MODELVIEW);
79         glLoadIdentity();
80         check_error();
81
82         // Draw the texture stretched over a long quad, interpolating it out.
83         // Note that since the texel center is in (0.5), we need to adjust the
84         // texture coordinates in order not to get long stretches of (1,1,1,...)
85         // at the start and (...,0,0,0) at the end.
86         glBegin(GL_QUADS);
87
88         glTexCoord1f(0.25f);
89         glVertex2f(0.0f, 0.0f);
90
91         glTexCoord1f(0.75f);
92         glVertex2f(1.0f, 0.0f);
93
94         glTexCoord1f(0.75f);
95         glVertex2f(1.0f, 1.0f);
96
97         glTexCoord1f(0.25f);
98         glVertex2f(0.0f, 1.0f);
99
100         glEnd();
101         check_error();
102
103         glDisable(GL_TEXTURE_1D);
104         check_error();
105
106         // Now read the data back and see what the card did.
107         // (We only look at the red channel; the others will surely be the same.)
108         // We assume a linear ramp; anything else will give sort of odd results here.
109         float out_data[width];
110         glReadPixels(0, 0, width, 1, GL_RED, GL_FLOAT, out_data);
111         check_error();
112
113         float biggest_jump = 0.0f;
114         for (unsigned i = 1; i < width; ++i) {
115                 assert(out_data[i] >= out_data[i - 1]);
116                 biggest_jump = std::max(biggest_jump, out_data[i] - out_data[i - 1]);
117         }
118
119         movit_texel_subpixel_precision = biggest_jump;
120
121         // Clean up.
122         glBindTexture(GL_TEXTURE_1D, 0);
123         check_error();
124         glBindFramebuffer(GL_FRAMEBUFFER, 0);
125         check_error();
126         glDeleteFramebuffers(1, &fbo);
127         check_error();
128         glDeleteTextures(1, &dst_texnum);
129         check_error();
130         glDeleteTextures(1, &src_texnum);
131         check_error();
132 }
133
134 void check_extensions()
135 {
136         // We fundamentally need FBOs and floating-point textures.
137         assert(glewIsSupported("GL_ARB_framebuffer_object") != 0);
138         assert(glewIsSupported("GL_ARB_texture_float") != 0);
139
140         // We assume that we can use non-power-of-two textures without restrictions.
141         assert(glewIsSupported("GL_ARB_texture_non_power_of_two") != 0);
142
143         // We also need GLSL fragment shaders.
144         assert(glewIsSupported("GL_ARB_fragment_shader") != 0);
145         assert(glewIsSupported("GL_ARB_shading_language_100") != 0);
146
147         // FlatInput and YCbCrInput uses PBOs. (They could in theory do without,
148         // but no modern card would really not provide it.)
149         assert(glewIsSupported("GL_ARB_pixel_buffer_object") != 0);
150
151         // ResampleEffect uses RG textures to encode a two-component LUT.
152         assert(glewIsSupported("GL_ARB_texture_rg") != 0);
153
154         // sRGB texture decode would be nice, but are not mandatory
155         // (GammaExpansionEffect can do the same thing if needed).
156         movit_srgb_textures_supported = glewIsSupported("GL_EXT_texture_sRGB");
157 }
158
159 }  // namespace
160
161 void init_movit(const std::string& data_directory, MovitDebugLevel debug_level)
162 {
163         if (movit_initialized) {
164                 return;
165         }
166
167         movit_data_directory = new std::string(data_directory);
168         movit_debug_level = debug_level;
169
170         glewInit();
171
172         // geez 
173         glPixelStorei(GL_PACK_ALIGNMENT, 1);
174         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
175
176         measure_texel_subpixel_precision();
177         check_extensions();
178
179         movit_initialized = true;
180 }