]> git.sesse.net Git - movit/blob - effect_chain.cpp
efd4abc49a611c233164089858d586a0538d075b
[movit] / effect_chain.cpp
1 #include <epoxy/gl.h>
2 #include <assert.h>
3 #include <math.h>
4 #include <stddef.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <algorithm>
9 #include <set>
10 #include <stack>
11 #include <utility>
12 #include <vector>
13 #include <Eigen/Core>
14
15 #include "alpha_division_effect.h"
16 #include "alpha_multiplication_effect.h"
17 #include "colorspace_conversion_effect.h"
18 #include "dither_effect.h"
19 #include "effect.h"
20 #include "effect_chain.h"
21 #include "effect_util.h"
22 #include "gamma_compression_effect.h"
23 #include "gamma_expansion_effect.h"
24 #include "init.h"
25 #include "input.h"
26 #include "resource_pool.h"
27 #include "util.h"
28 #include "ycbcr_conversion_effect.h"
29
30 using namespace Eigen;
31 using namespace std;
32
33 namespace movit {
34
35 EffectChain::EffectChain(float aspect_nom, float aspect_denom, ResourcePool *resource_pool)
36         : aspect_nom(aspect_nom),
37           aspect_denom(aspect_denom),
38           output_color_rgba(false),
39           num_output_color_ycbcr(0),
40           dither_effect(NULL),
41           ycbcr_conversion_effect_node(NULL),
42           intermediate_format(GL_RGBA16F),
43           intermediate_transformation(NO_FRAMEBUFFER_TRANSFORMATION),
44           num_dither_bits(0),
45           output_origin(OUTPUT_ORIGIN_BOTTOM_LEFT),
46           finalized(false),
47           resource_pool(resource_pool),
48           do_phase_timing(false) {
49         if (resource_pool == NULL) {
50                 this->resource_pool = new ResourcePool();
51                 owns_resource_pool = true;
52         } else {
53                 owns_resource_pool = false;
54         }
55
56         // Generate a VBO with some data in (shared position and texture coordinate data).
57         float vertices[] = {
58                 0.0f, 2.0f,
59                 0.0f, 0.0f,
60                 2.0f, 0.0f
61         };
62         vbo = generate_vbo(2, GL_FLOAT, sizeof(vertices), vertices);
63 }
64
65 EffectChain::~EffectChain()
66 {
67         for (unsigned i = 0; i < nodes.size(); ++i) {
68                 delete nodes[i]->effect;
69                 delete nodes[i];
70         }
71         for (unsigned i = 0; i < phases.size(); ++i) {
72                 resource_pool->release_glsl_program(phases[i]->glsl_program_num);
73                 delete phases[i];
74         }
75         if (owns_resource_pool) {
76                 delete resource_pool;
77         }
78         glDeleteBuffers(1, &vbo);
79         check_error();
80 }
81
82 Input *EffectChain::add_input(Input *input)
83 {
84         assert(!finalized);
85         inputs.push_back(input);
86         add_node(input);
87         return input;
88 }
89
90 void EffectChain::add_output(const ImageFormat &format, OutputAlphaFormat alpha_format)
91 {
92         assert(!finalized);
93         assert(!output_color_rgba);
94         output_format = format;
95         output_alpha_format = alpha_format;
96         output_color_rgba = true;
97 }
98
99 void EffectChain::add_ycbcr_output(const ImageFormat &format, OutputAlphaFormat alpha_format,
100                                    const YCbCrFormat &ycbcr_format, YCbCrOutputSplitting output_splitting,
101                                    GLenum output_type)
102 {
103         assert(!finalized);
104         assert(num_output_color_ycbcr < 2);
105         output_format = format;
106         output_alpha_format = alpha_format;
107
108         if (num_output_color_ycbcr == 1) {
109                 // Check that the format is the same.
110                 assert(output_ycbcr_format.luma_coefficients == ycbcr_format.luma_coefficients);
111                 assert(output_ycbcr_format.full_range == ycbcr_format.full_range);
112                 assert(output_ycbcr_format.num_levels == ycbcr_format.num_levels);
113                 assert(output_ycbcr_format.chroma_subsampling_x == 1);
114                 assert(output_ycbcr_format.chroma_subsampling_y == 1);
115                 assert(output_ycbcr_type == output_type);
116         } else {
117                 output_ycbcr_format = ycbcr_format;
118                 output_ycbcr_type = output_type;
119         }
120         output_ycbcr_splitting[num_output_color_ycbcr++] = output_splitting;
121
122         assert(ycbcr_format.chroma_subsampling_x == 1);
123         assert(ycbcr_format.chroma_subsampling_y == 1);
124 }
125
126 void EffectChain::change_ycbcr_output_format(const YCbCrFormat &ycbcr_format)
127 {
128         assert(num_output_color_ycbcr > 0);
129         assert(output_ycbcr_format.chroma_subsampling_x == 1);
130         assert(output_ycbcr_format.chroma_subsampling_y == 1);
131
132         output_ycbcr_format = ycbcr_format;
133         if (finalized) {
134                 YCbCrConversionEffect *effect = (YCbCrConversionEffect *)(ycbcr_conversion_effect_node->effect);
135                 effect->change_output_format(ycbcr_format);
136         }
137 }
138
139 Node *EffectChain::add_node(Effect *effect)
140 {
141         for (unsigned i = 0; i < nodes.size(); ++i) {
142                 assert(nodes[i]->effect != effect);
143         }
144
145         Node *node = new Node;
146         node->effect = effect;
147         node->disabled = false;
148         node->output_color_space = COLORSPACE_INVALID;
149         node->output_gamma_curve = GAMMA_INVALID;
150         node->output_alpha_type = ALPHA_INVALID;
151         node->needs_mipmaps = false;
152         node->one_to_one_sampling = false;
153
154         nodes.push_back(node);
155         node_map[effect] = node;
156         effect->inform_added(this);
157         return node;
158 }
159
160 void EffectChain::connect_nodes(Node *sender, Node *receiver)
161 {
162         sender->outgoing_links.push_back(receiver);
163         receiver->incoming_links.push_back(sender);
164 }
165
166 void EffectChain::replace_receiver(Node *old_receiver, Node *new_receiver)
167 {
168         new_receiver->incoming_links = old_receiver->incoming_links;
169         old_receiver->incoming_links.clear();
170         
171         for (unsigned i = 0; i < new_receiver->incoming_links.size(); ++i) {
172                 Node *sender = new_receiver->incoming_links[i];
173                 for (unsigned j = 0; j < sender->outgoing_links.size(); ++j) {
174                         if (sender->outgoing_links[j] == old_receiver) {
175                                 sender->outgoing_links[j] = new_receiver;
176                         }
177                 }
178         }       
179 }
180
181 void EffectChain::replace_sender(Node *old_sender, Node *new_sender)
182 {
183         new_sender->outgoing_links = old_sender->outgoing_links;
184         old_sender->outgoing_links.clear();
185         
186         for (unsigned i = 0; i < new_sender->outgoing_links.size(); ++i) {
187                 Node *receiver = new_sender->outgoing_links[i];
188                 for (unsigned j = 0; j < receiver->incoming_links.size(); ++j) {
189                         if (receiver->incoming_links[j] == old_sender) {
190                                 receiver->incoming_links[j] = new_sender;
191                         }
192                 }
193         }       
194 }
195
196 void EffectChain::insert_node_between(Node *sender, Node *middle, Node *receiver)
197 {
198         for (unsigned i = 0; i < sender->outgoing_links.size(); ++i) {
199                 if (sender->outgoing_links[i] == receiver) {
200                         sender->outgoing_links[i] = middle;
201                         middle->incoming_links.push_back(sender);
202                 }
203         }
204         for (unsigned i = 0; i < receiver->incoming_links.size(); ++i) {
205                 if (receiver->incoming_links[i] == sender) {
206                         receiver->incoming_links[i] = middle;
207                         middle->outgoing_links.push_back(receiver);
208                 }
209         }
210
211         assert(middle->incoming_links.size() == middle->effect->num_inputs());
212 }
213
214 GLenum EffectChain::get_input_sampler(Node *node, unsigned input_num) const
215 {
216         assert(node->effect->needs_texture_bounce());
217         assert(input_num < node->incoming_links.size());
218         assert(node->incoming_links[input_num]->bound_sampler_num >= 0);
219         assert(node->incoming_links[input_num]->bound_sampler_num < 8);
220         return GL_TEXTURE0 + node->incoming_links[input_num]->bound_sampler_num;
221 }
222
223 GLenum EffectChain::has_input_sampler(Node *node, unsigned input_num) const
224 {
225         assert(input_num < node->incoming_links.size());
226         return node->incoming_links[input_num]->bound_sampler_num >= 0 &&
227                 node->incoming_links[input_num]->bound_sampler_num < 8;
228 }
229
230 void EffectChain::find_all_nonlinear_inputs(Node *node, vector<Node *> *nonlinear_inputs)
231 {
232         if (node->output_gamma_curve == GAMMA_LINEAR &&
233             node->effect->effect_type_id() != "GammaCompressionEffect") {
234                 return;
235         }
236         if (node->effect->num_inputs() == 0) {
237                 nonlinear_inputs->push_back(node);
238         } else {
239                 assert(node->effect->num_inputs() == node->incoming_links.size());
240                 for (unsigned i = 0; i < node->incoming_links.size(); ++i) {
241                         find_all_nonlinear_inputs(node->incoming_links[i], nonlinear_inputs);
242                 }
243         }
244 }
245
246 Effect *EffectChain::add_effect(Effect *effect, const vector<Effect *> &inputs)
247 {
248         assert(!finalized);
249         assert(inputs.size() == effect->num_inputs());
250         Node *node = add_node(effect);
251         for (unsigned i = 0; i < inputs.size(); ++i) {
252                 assert(node_map.count(inputs[i]) != 0);
253                 connect_nodes(node_map[inputs[i]], node);
254         }
255         return effect;
256 }
257
258 // ESSL doesn't support token pasting. Replace PREFIX(x) with <effect_id>_x.
259 string replace_prefix(const string &text, const string &prefix)
260 {
261         string output;
262         size_t start = 0;
263
264         while (start < text.size()) {
265                 size_t pos = text.find("PREFIX(", start);
266                 if (pos == string::npos) {
267                         output.append(text.substr(start, string::npos));
268                         break;
269                 }
270
271                 output.append(text.substr(start, pos - start));
272                 output.append(prefix);
273                 output.append("_");
274
275                 pos += strlen("PREFIX(");
276         
277                 // Output stuff until we find the matching ), which we then eat.
278                 int depth = 1;
279                 size_t end_arg_pos = pos;
280                 while (end_arg_pos < text.size()) {
281                         if (text[end_arg_pos] == '(') {
282                                 ++depth;
283                         } else if (text[end_arg_pos] == ')') {
284                                 --depth;
285                                 if (depth == 0) {
286                                         break;
287                                 }
288                         }
289                         ++end_arg_pos;
290                 }
291                 output.append(text.substr(pos, end_arg_pos - pos));
292                 ++end_arg_pos;
293                 assert(depth == 0);
294                 start = end_arg_pos;
295         }
296         return output;
297 }
298
299 namespace {
300
301 template<class T>
302 void extract_uniform_declarations(const vector<Uniform<T> > &effect_uniforms,
303                                   const string &type_specifier,
304                                   const string &effect_id,
305                                   vector<Uniform<T> > *phase_uniforms,
306                                   string *glsl_string)
307 {
308         for (unsigned i = 0; i < effect_uniforms.size(); ++i) {
309                 phase_uniforms->push_back(effect_uniforms[i]);
310                 phase_uniforms->back().prefix = effect_id;
311
312                 *glsl_string += string("uniform ") + type_specifier + " " + effect_id
313                         + "_" + effect_uniforms[i].name + ";\n";
314         }
315 }
316
317 template<class T>
318 void extract_uniform_array_declarations(const vector<Uniform<T> > &effect_uniforms,
319                                         const string &type_specifier,
320                                         const string &effect_id,
321                                         vector<Uniform<T> > *phase_uniforms,
322                                         string *glsl_string)
323 {
324         for (unsigned i = 0; i < effect_uniforms.size(); ++i) {
325                 phase_uniforms->push_back(effect_uniforms[i]);
326                 phase_uniforms->back().prefix = effect_id;
327
328                 char buf[256];
329                 snprintf(buf, sizeof(buf), "uniform %s %s_%s[%d];\n",
330                         type_specifier.c_str(), effect_id.c_str(),
331                         effect_uniforms[i].name.c_str(),
332                         int(effect_uniforms[i].num_values));
333                 *glsl_string += buf;
334         }
335 }
336
337 template<class T>
338 void collect_uniform_locations(GLuint glsl_program_num, vector<Uniform<T> > *phase_uniforms)
339 {
340         for (unsigned i = 0; i < phase_uniforms->size(); ++i) {
341                 Uniform<T> &uniform = (*phase_uniforms)[i];
342                 uniform.location = get_uniform_location(glsl_program_num, uniform.prefix, uniform.name);
343         }
344 }
345
346 }  // namespace
347
348 void EffectChain::compile_glsl_program(Phase *phase)
349 {
350         string frag_shader_header = read_version_dependent_file("header", "frag");
351         string frag_shader = "";
352
353         // Create functions and uniforms for all the texture inputs that we need.
354         for (unsigned i = 0; i < phase->inputs.size(); ++i) {
355                 Node *input = phase->inputs[i]->output_node;
356                 char effect_id[256];
357                 sprintf(effect_id, "in%u", i);
358                 phase->effect_ids.insert(make_pair(input, effect_id));
359         
360                 frag_shader += string("uniform sampler2D tex_") + effect_id + ";\n";
361                 frag_shader += string("vec4 ") + effect_id + "(vec2 tc) {\n";
362                 frag_shader += "\tvec4 tmp = tex2D(tex_" + string(effect_id) + ", tc);\n";
363
364                 if (intermediate_transformation == SQUARE_ROOT_FRAMEBUFFER_TRANSFORMATION &&
365                     phase->inputs[i]->output_node->output_gamma_curve == GAMMA_LINEAR) {
366                         frag_shader += "\ttmp.rgb *= tmp.rgb;\n";
367                 }
368
369                 frag_shader += "\treturn tmp;\n";
370                 frag_shader += "}\n";
371                 frag_shader += "\n";
372
373                 Uniform<int> uniform;
374                 uniform.name = effect_id;
375                 uniform.value = &phase->input_samplers[i];
376                 uniform.prefix = "tex";
377                 uniform.num_values = 1;
378                 uniform.location = -1;
379                 phase->uniforms_sampler2d.push_back(uniform);
380         }
381
382         // Give each effect in the phase its own ID.
383         for (unsigned i = 0; i < phase->effects.size(); ++i) {
384                 Node *node = phase->effects[i];
385                 char effect_id[256];
386                 sprintf(effect_id, "eff%u", i);
387                 phase->effect_ids.insert(make_pair(node, effect_id));
388         }
389
390         for (unsigned i = 0; i < phase->effects.size(); ++i) {
391                 Node *node = phase->effects[i];
392                 const string effect_id = phase->effect_ids[node];
393                 if (node->incoming_links.size() == 1) {
394                         frag_shader += string("#define INPUT ") + phase->effect_ids[node->incoming_links[0]] + "\n";
395                 } else {
396                         for (unsigned j = 0; j < node->incoming_links.size(); ++j) {
397                                 char buf[256];
398                                 sprintf(buf, "#define INPUT%d %s\n", j + 1, phase->effect_ids[node->incoming_links[j]].c_str());
399                                 frag_shader += buf;
400                         }
401                 }
402         
403                 frag_shader += "\n";
404                 frag_shader += string("#define FUNCNAME ") + effect_id + "\n";
405                 frag_shader += replace_prefix(node->effect->output_fragment_shader(), effect_id);
406                 frag_shader += "#undef PREFIX\n";
407                 frag_shader += "#undef FUNCNAME\n";
408                 if (node->incoming_links.size() == 1) {
409                         frag_shader += "#undef INPUT\n";
410                 } else {
411                         for (unsigned j = 0; j < node->incoming_links.size(); ++j) {
412                                 char buf[256];
413                                 sprintf(buf, "#undef INPUT%d\n", j + 1);
414                                 frag_shader += buf;
415                         }
416                 }
417                 frag_shader += "\n";
418         }
419         frag_shader += string("#define INPUT ") + phase->effect_ids[phase->effects.back()] + "\n";
420
421         // If we're the last phase, add the right #defines for Y'CbCr multi-output as needed.
422         vector<string> frag_shader_outputs;  // In order.
423         if (phase->output_node->outgoing_links.empty() && num_output_color_ycbcr > 0) {
424                 switch (output_ycbcr_splitting[0]) {
425                 case YCBCR_OUTPUT_INTERLEAVED:
426                         // No #defines set.
427                         frag_shader_outputs.push_back("FragColor");
428                         break;
429                 case YCBCR_OUTPUT_SPLIT_Y_AND_CBCR:
430                         frag_shader += "#define YCBCR_OUTPUT_SPLIT_Y_AND_CBCR 1\n";
431                         frag_shader_outputs.push_back("Y");
432                         frag_shader_outputs.push_back("Chroma");
433                         break;
434                 case YCBCR_OUTPUT_PLANAR:
435                         frag_shader += "#define YCBCR_OUTPUT_PLANAR 1\n";
436                         frag_shader_outputs.push_back("Y");
437                         frag_shader_outputs.push_back("Cb");
438                         frag_shader_outputs.push_back("Cr");
439                         break;
440                 default:
441                         assert(false);
442                 }
443
444                 if (num_output_color_ycbcr > 1) {
445                         switch (output_ycbcr_splitting[1]) {
446                         case YCBCR_OUTPUT_INTERLEAVED:
447                                 frag_shader += "#define SECOND_YCBCR_OUTPUT_INTERLEAVED 1\n";
448                                 frag_shader_outputs.push_back("YCbCr2");
449                                 break;
450                         case YCBCR_OUTPUT_SPLIT_Y_AND_CBCR:
451                                 frag_shader += "#define SECOND_YCBCR_OUTPUT_SPLIT_Y_AND_CBCR 1\n";
452                                 frag_shader_outputs.push_back("Y2");
453                                 frag_shader_outputs.push_back("Chroma2");
454                                 break;
455                         case YCBCR_OUTPUT_PLANAR:
456                                 frag_shader += "#define SECOND_YCBCR_OUTPUT_PLANAR 1\n";
457                                 frag_shader_outputs.push_back("Y2");
458                                 frag_shader_outputs.push_back("Cb2");
459                                 frag_shader_outputs.push_back("Cr2");
460                                 break;
461                         default:
462                                 assert(false);
463                         }
464                 }
465
466                 if (output_color_rgba) {
467                         // Note: Needs to come in the header, because not only the
468                         // output needs to see it (YCbCrConversionEffect and DitherEffect
469                         // do, too).
470                         frag_shader_header += "#define YCBCR_ALSO_OUTPUT_RGBA 1\n";
471                         frag_shader_outputs.push_back("RGBA");
472                 }
473         }
474
475         // If we're bouncing to a temporary texture, signal transformation if desired.
476         if (!phase->output_node->outgoing_links.empty()) {
477                 if (intermediate_transformation == SQUARE_ROOT_FRAMEBUFFER_TRANSFORMATION &&
478                     phase->output_node->output_gamma_curve == GAMMA_LINEAR) {
479                         frag_shader += "#define SQUARE_ROOT_TRANSFORMATION 1\n";
480                 }
481         }
482
483         frag_shader.append(read_file("footer.frag"));
484
485         // Collect uniforms from all effects and output them. Note that this needs
486         // to happen after output_fragment_shader(), even though the uniforms come
487         // before in the output source, since output_fragment_shader() is allowed
488         // to register new uniforms (e.g. arrays that are of unknown length until
489         // finalization time).
490         // TODO: Make a uniform block for platforms that support it.
491         string frag_shader_uniforms = "";
492         for (unsigned i = 0; i < phase->effects.size(); ++i) {
493                 Node *node = phase->effects[i];
494                 Effect *effect = node->effect;
495                 const string effect_id = phase->effect_ids[node];
496                 extract_uniform_declarations(effect->uniforms_sampler2d, "sampler2D", effect_id, &phase->uniforms_sampler2d, &frag_shader_uniforms);
497                 extract_uniform_declarations(effect->uniforms_bool, "bool", effect_id, &phase->uniforms_bool, &frag_shader_uniforms);
498                 extract_uniform_declarations(effect->uniforms_int, "int", effect_id, &phase->uniforms_int, &frag_shader_uniforms);
499                 extract_uniform_declarations(effect->uniforms_float, "float", effect_id, &phase->uniforms_float, &frag_shader_uniforms);
500                 extract_uniform_declarations(effect->uniforms_vec2, "vec2", effect_id, &phase->uniforms_vec2, &frag_shader_uniforms);
501                 extract_uniform_declarations(effect->uniforms_vec3, "vec3", effect_id, &phase->uniforms_vec3, &frag_shader_uniforms);
502                 extract_uniform_declarations(effect->uniforms_vec4, "vec4", effect_id, &phase->uniforms_vec4, &frag_shader_uniforms);
503                 extract_uniform_array_declarations(effect->uniforms_float_array, "float", effect_id, &phase->uniforms_float, &frag_shader_uniforms);
504                 extract_uniform_array_declarations(effect->uniforms_vec2_array, "vec2", effect_id, &phase->uniforms_vec2, &frag_shader_uniforms);
505                 extract_uniform_array_declarations(effect->uniforms_vec3_array, "vec3", effect_id, &phase->uniforms_vec3, &frag_shader_uniforms);
506                 extract_uniform_array_declarations(effect->uniforms_vec4_array, "vec4", effect_id, &phase->uniforms_vec4, &frag_shader_uniforms);
507                 extract_uniform_declarations(effect->uniforms_mat3, "mat3", effect_id, &phase->uniforms_mat3, &frag_shader_uniforms);
508         }
509
510         frag_shader = frag_shader_header + frag_shader_uniforms + frag_shader;
511
512         string vert_shader = read_version_dependent_file("vs", "vert");
513
514         // If we're the last phase and need to flip the picture to compensate for
515         // the origin, tell the vertex shader so.
516         if (phase->output_node->outgoing_links.empty() && output_origin == OUTPUT_ORIGIN_TOP_LEFT) {
517                 const string needle = "#define FLIP_ORIGIN 0";
518                 size_t pos = vert_shader.find(needle);
519                 assert(pos != string::npos);
520
521                 vert_shader[pos + needle.size() - 1] = '1';
522         }
523
524         phase->glsl_program_num = resource_pool->compile_glsl_program(vert_shader, frag_shader, frag_shader_outputs);
525         GLint position_attribute_index = glGetAttribLocation(phase->glsl_program_num, "position");
526         GLint texcoord_attribute_index = glGetAttribLocation(phase->glsl_program_num, "texcoord");
527         if (position_attribute_index != -1) {
528                 phase->attribute_indexes.insert(position_attribute_index);
529         }
530         if (texcoord_attribute_index != -1) {
531                 phase->attribute_indexes.insert(texcoord_attribute_index);
532         }
533
534         // Collect the resulting location numbers for each uniform.
535         collect_uniform_locations(phase->glsl_program_num, &phase->uniforms_sampler2d);
536         collect_uniform_locations(phase->glsl_program_num, &phase->uniforms_bool);
537         collect_uniform_locations(phase->glsl_program_num, &phase->uniforms_int);
538         collect_uniform_locations(phase->glsl_program_num, &phase->uniforms_float);
539         collect_uniform_locations(phase->glsl_program_num, &phase->uniforms_vec2);
540         collect_uniform_locations(phase->glsl_program_num, &phase->uniforms_vec3);
541         collect_uniform_locations(phase->glsl_program_num, &phase->uniforms_vec4);
542         collect_uniform_locations(phase->glsl_program_num, &phase->uniforms_mat3);
543 }
544
545 // Construct GLSL programs, starting at the given effect and following
546 // the chain from there. We end a program every time we come to an effect
547 // marked as "needs texture bounce", one that is used by multiple other
548 // effects, every time we need to bounce due to output size change
549 // (not all size changes require ending), and of course at the end.
550 //
551 // We follow a quite simple depth-first search from the output, although
552 // without recursing explicitly within each phase.
553 Phase *EffectChain::construct_phase(Node *output, map<Node *, Phase *> *completed_effects)
554 {
555         if (completed_effects->count(output)) {
556                 return (*completed_effects)[output];
557         }
558
559         Phase *phase = new Phase;
560         phase->output_node = output;
561
562         // If the output effect has one-to-one sampling, we try to trace this
563         // status down through the dependency chain. This is important in case
564         // we hit an effect that changes output size (and not sets a virtual
565         // output size); if we have one-to-one sampling, we don't have to break
566         // the phase.
567         output->one_to_one_sampling = output->effect->one_to_one_sampling();
568
569         // Effects that we have yet to calculate, but that we know should
570         // be in the current phase.
571         stack<Node *> effects_todo_this_phase;
572         effects_todo_this_phase.push(output);
573
574         while (!effects_todo_this_phase.empty()) {
575                 Node *node = effects_todo_this_phase.top();
576                 effects_todo_this_phase.pop();
577
578                 if (node->effect->needs_mipmaps()) {
579                         node->needs_mipmaps = true;
580                 }
581
582                 // This should currently only happen for effects that are inputs
583                 // (either true inputs or phase outputs). We special-case inputs,
584                 // and then deduplicate phase outputs below.
585                 if (node->effect->num_inputs() == 0) {
586                         if (find(phase->effects.begin(), phase->effects.end(), node) != phase->effects.end()) {
587                                 continue;
588                         }
589                 } else {
590                         assert(completed_effects->count(node) == 0);
591                 }
592
593                 phase->effects.push_back(node);
594
595                 // Find all the dependencies of this effect, and add them to the stack.
596                 vector<Node *> deps = node->incoming_links;
597                 assert(node->effect->num_inputs() == deps.size());
598                 for (unsigned i = 0; i < deps.size(); ++i) {
599                         bool start_new_phase = false;
600
601                         if (node->effect->needs_texture_bounce() &&
602                             !deps[i]->effect->is_single_texture() &&
603                             !deps[i]->effect->override_disable_bounce()) {
604                                 start_new_phase = true;
605                         }
606
607                         // Propagate information about needing mipmaps down the chain,
608                         // breaking the phase if we notice an incompatibility.
609                         //
610                         // Note that we cannot do this propagation as a normal pass,
611                         // because it needs information about where the phases end
612                         // (we should not propagate the flag across phases).
613                         if (node->needs_mipmaps) {
614                                 if (deps[i]->effect->num_inputs() == 0) {
615                                         Input *input = static_cast<Input *>(deps[i]->effect);
616                                         start_new_phase |= !input->can_supply_mipmaps();
617                                 } else {
618                                         deps[i]->needs_mipmaps = true;
619                                 }
620                         }
621
622                         if (deps[i]->outgoing_links.size() > 1) {
623                                 if (!deps[i]->effect->is_single_texture()) {
624                                         // More than one effect uses this as the input,
625                                         // and it is not a texture itself.
626                                         // The easiest thing to do (and probably also the safest
627                                         // performance-wise in most cases) is to bounce it to a texture
628                                         // and then let the next passes read from that.
629                                         start_new_phase = true;
630                                 } else {
631                                         assert(deps[i]->effect->num_inputs() == 0);
632
633                                         // For textures, we try to be slightly more clever;
634                                         // if none of our outputs need a bounce, we don't bounce
635                                         // but instead simply use the effect many times.
636                                         //
637                                         // Strictly speaking, we could bounce it for some outputs
638                                         // and use it directly for others, but the processing becomes
639                                         // somewhat simpler if the effect is only used in one such way.
640                                         for (unsigned j = 0; j < deps[i]->outgoing_links.size(); ++j) {
641                                                 Node *rdep = deps[i]->outgoing_links[j];
642                                                 start_new_phase |= rdep->effect->needs_texture_bounce();
643                                         }
644                                 }
645                         }
646
647                         if (deps[i]->effect->sets_virtual_output_size()) {
648                                 assert(deps[i]->effect->changes_output_size());
649                                 // If the next effect sets a virtual size to rely on OpenGL's
650                                 // bilinear sampling, we'll really need to break the phase here.
651                                 start_new_phase = true;
652                         } else if (deps[i]->effect->changes_output_size() && !node->one_to_one_sampling) {
653                                 // If the next effect changes size and we don't have one-to-one sampling,
654                                 // we also need to break here.
655                                 start_new_phase = true;
656                         }
657
658                         if (start_new_phase) {
659                                 phase->inputs.push_back(construct_phase(deps[i], completed_effects));
660                         } else {
661                                 effects_todo_this_phase.push(deps[i]);
662
663                                 // Propagate the one-to-one status down through the dependency.
664                                 deps[i]->one_to_one_sampling = node->one_to_one_sampling &&
665                                         deps[i]->effect->one_to_one_sampling();
666                         }
667                 }
668         }
669
670         // No more effects to do this phase. Take all the ones we have,
671         // and create a GLSL program for it.
672         assert(!phase->effects.empty());
673
674         // Deduplicate the inputs, but don't change the ordering e.g. by sorting;
675         // that would be nondeterministic and thus reduce cacheability.
676         // TODO: Make this even more deterministic.
677         vector<Phase *> dedup_inputs;
678         set<Phase *> seen_inputs;
679         for (size_t i = 0; i < phase->inputs.size(); ++i) {
680                 if (seen_inputs.insert(phase->inputs[i]).second) {
681                         dedup_inputs.push_back(phase->inputs[i]);
682                 }
683         }
684         swap(phase->inputs, dedup_inputs);
685
686         // Allocate samplers for each input.
687         phase->input_samplers.resize(phase->inputs.size());
688
689         // We added the effects from the output and back, but we need to output
690         // them in topological sort order in the shader.
691         phase->effects = topological_sort(phase->effects);
692
693         // Figure out if we need mipmaps or not, and if so, tell the inputs that.
694         phase->input_needs_mipmaps = false;
695         for (unsigned i = 0; i < phase->effects.size(); ++i) {
696                 Node *node = phase->effects[i];
697                 phase->input_needs_mipmaps |= node->effect->needs_mipmaps();
698         }
699         for (unsigned i = 0; i < phase->effects.size(); ++i) {
700                 Node *node = phase->effects[i];
701                 if (node->effect->num_inputs() == 0) {
702                         Input *input = static_cast<Input *>(node->effect);
703                         assert(!phase->input_needs_mipmaps || input->can_supply_mipmaps());
704                         CHECK(input->set_int("needs_mipmaps", phase->input_needs_mipmaps));
705                 }
706         }
707
708         // Tell each node which phase it ended up in, so that the unit test
709         // can check that the phases were split in the right place.
710         // Note that this ignores that effects may be part of multiple phases;
711         // if the unit tests need to test such cases, we'll reconsider.
712         for (unsigned i = 0; i < phase->effects.size(); ++i) {
713                 phase->effects[i]->containing_phase = phase;
714         }
715
716         // Actually make the shader for this phase.
717         compile_glsl_program(phase);
718
719         // Initialize timers.
720         if (movit_timer_queries_supported) {
721                 phase->time_elapsed_ns = 0;
722                 phase->num_measured_iterations = 0;
723         }
724
725         assert(completed_effects->count(output) == 0);
726         completed_effects->insert(make_pair(output, phase));
727         phases.push_back(phase);
728         return phase;
729 }
730
731 void EffectChain::output_dot(const char *filename)
732 {
733         if (movit_debug_level != MOVIT_DEBUG_ON) {
734                 return;
735         }
736
737         FILE *fp = fopen(filename, "w");
738         if (fp == NULL) {
739                 perror(filename);
740                 exit(1);
741         }
742
743         fprintf(fp, "digraph G {\n");
744         fprintf(fp, "  output [shape=box label=\"(output)\"];\n");
745         for (unsigned i = 0; i < nodes.size(); ++i) {
746                 // Find out which phase this event belongs to.
747                 vector<int> in_phases;
748                 for (unsigned j = 0; j < phases.size(); ++j) {
749                         const Phase* p = phases[j];
750                         if (find(p->effects.begin(), p->effects.end(), nodes[i]) != p->effects.end()) {
751                                 in_phases.push_back(j);
752                         }
753                 }
754
755                 if (in_phases.empty()) {
756                         fprintf(fp, "  n%ld [label=\"%s\"];\n", (long)nodes[i], nodes[i]->effect->effect_type_id().c_str());
757                 } else if (in_phases.size() == 1) {
758                         fprintf(fp, "  n%ld [label=\"%s\" style=\"filled\" fillcolor=\"/accent8/%d\"];\n",
759                                 (long)nodes[i], nodes[i]->effect->effect_type_id().c_str(),
760                                 (in_phases[0] % 8) + 1);
761                 } else {
762                         // If we had new enough Graphviz, style="wedged" would probably be ideal here.
763                         // But alas.
764                         fprintf(fp, "  n%ld [label=\"%s [in multiple phases]\" style=\"filled\" fillcolor=\"/accent8/%d\"];\n",
765                                 (long)nodes[i], nodes[i]->effect->effect_type_id().c_str(),
766                                 (in_phases[0] % 8) + 1);
767                 }
768
769                 char from_node_id[256];
770                 snprintf(from_node_id, 256, "n%ld", (long)nodes[i]);
771
772                 for (unsigned j = 0; j < nodes[i]->outgoing_links.size(); ++j) {
773                         char to_node_id[256];
774                         snprintf(to_node_id, 256, "n%ld", (long)nodes[i]->outgoing_links[j]);
775
776                         vector<string> labels = get_labels_for_edge(nodes[i], nodes[i]->outgoing_links[j]);
777                         output_dot_edge(fp, from_node_id, to_node_id, labels);
778                 }
779
780                 if (nodes[i]->outgoing_links.empty() && !nodes[i]->disabled) {
781                         // Output node.
782                         vector<string> labels = get_labels_for_edge(nodes[i], NULL);
783                         output_dot_edge(fp, from_node_id, "output", labels);
784                 }
785         }
786         fprintf(fp, "}\n");
787
788         fclose(fp);
789 }
790
791 vector<string> EffectChain::get_labels_for_edge(const Node *from, const Node *to)
792 {
793         vector<string> labels;
794
795         if (to != NULL && to->effect->needs_texture_bounce()) {
796                 labels.push_back("needs_bounce");
797         }
798         if (from->effect->changes_output_size()) {
799                 labels.push_back("resize");
800         }
801
802         switch (from->output_color_space) {
803         case COLORSPACE_INVALID:
804                 labels.push_back("spc[invalid]");
805                 break;
806         case COLORSPACE_REC_601_525:
807                 labels.push_back("spc[rec601-525]");
808                 break;
809         case COLORSPACE_REC_601_625:
810                 labels.push_back("spc[rec601-625]");
811                 break;
812         default:
813                 break;
814         }
815
816         switch (from->output_gamma_curve) {
817         case GAMMA_INVALID:
818                 labels.push_back("gamma[invalid]");
819                 break;
820         case GAMMA_sRGB:
821                 labels.push_back("gamma[sRGB]");
822                 break;
823         case GAMMA_REC_601:  // and GAMMA_REC_709
824                 labels.push_back("gamma[rec601/709]");
825                 break;
826         default:
827                 break;
828         }
829
830         switch (from->output_alpha_type) {
831         case ALPHA_INVALID:
832                 labels.push_back("alpha[invalid]");
833                 break;
834         case ALPHA_BLANK:
835                 labels.push_back("alpha[blank]");
836                 break;
837         case ALPHA_POSTMULTIPLIED:
838                 labels.push_back("alpha[postmult]");
839                 break;
840         default:
841                 break;
842         }
843
844         return labels;
845 }
846
847 void EffectChain::output_dot_edge(FILE *fp,
848                                   const string &from_node_id,
849                                   const string &to_node_id,
850                                   const vector<string> &labels)
851 {
852         if (labels.empty()) {
853                 fprintf(fp, "  %s -> %s;\n", from_node_id.c_str(), to_node_id.c_str());
854         } else {
855                 string label = labels[0];
856                 for (unsigned k = 1; k < labels.size(); ++k) {
857                         label += ", " + labels[k];
858                 }
859                 fprintf(fp, "  %s -> %s [label=\"%s\"];\n", from_node_id.c_str(), to_node_id.c_str(), label.c_str());
860         }
861 }
862
863 void EffectChain::size_rectangle_to_fit(unsigned width, unsigned height, unsigned *output_width, unsigned *output_height)
864 {
865         unsigned scaled_width, scaled_height;
866
867         if (float(width) * aspect_denom >= float(height) * aspect_nom) {
868                 // Same aspect, or W/H > aspect (image is wider than the frame).
869                 // In either case, keep width, and adjust height.
870                 scaled_width = width;
871                 scaled_height = lrintf(width * aspect_denom / aspect_nom);
872         } else {
873                 // W/H < aspect (image is taller than the frame), so keep height,
874                 // and adjust width.
875                 scaled_width = lrintf(height * aspect_nom / aspect_denom);
876                 scaled_height = height;
877         }
878
879         // We should be consistently larger or smaller then the existing choice,
880         // since we have the same aspect.
881         assert(!(scaled_width < *output_width && scaled_height > *output_height));
882         assert(!(scaled_height < *output_height && scaled_width > *output_width));
883
884         if (scaled_width >= *output_width && scaled_height >= *output_height) {
885                 *output_width = scaled_width;
886                 *output_height = scaled_height;
887         }
888 }
889
890 // Propagate input texture sizes throughout, and inform effects downstream.
891 // (Like a lot of other code, we depend on effects being in topological order.)
892 void EffectChain::inform_input_sizes(Phase *phase)
893 {
894         // All effects that have a defined size (inputs and RTT inputs)
895         // get that. Reset all others.
896         for (unsigned i = 0; i < phase->effects.size(); ++i) {
897                 Node *node = phase->effects[i];
898                 if (node->effect->num_inputs() == 0) {
899                         Input *input = static_cast<Input *>(node->effect);
900                         node->output_width = input->get_width();
901                         node->output_height = input->get_height();
902                         assert(node->output_width != 0);
903                         assert(node->output_height != 0);
904                 } else {
905                         node->output_width = node->output_height = 0;
906                 }
907         }
908         for (unsigned i = 0; i < phase->inputs.size(); ++i) {
909                 Phase *input = phase->inputs[i];
910                 input->output_node->output_width = input->virtual_output_width;
911                 input->output_node->output_height = input->virtual_output_height;
912                 assert(input->output_node->output_width != 0);
913                 assert(input->output_node->output_height != 0);
914         }
915
916         // Now propagate from the inputs towards the end, and inform as we go.
917         // The rules are simple:
918         //
919         //   1. Don't touch effects that already have given sizes (ie., inputs
920         //      or effects that change the output size).
921         //   2. If all of your inputs have the same size, that will be your output size.
922         //   3. Otherwise, your output size is 0x0.
923         for (unsigned i = 0; i < phase->effects.size(); ++i) {
924                 Node *node = phase->effects[i];
925                 if (node->effect->num_inputs() == 0) {
926                         continue;
927                 }
928                 unsigned this_output_width = 0;
929                 unsigned this_output_height = 0;
930                 for (unsigned j = 0; j < node->incoming_links.size(); ++j) {
931                         Node *input = node->incoming_links[j];
932                         node->effect->inform_input_size(j, input->output_width, input->output_height);
933                         if (j == 0) {
934                                 this_output_width = input->output_width;
935                                 this_output_height = input->output_height;
936                         } else if (input->output_width != this_output_width || input->output_height != this_output_height) {
937                                 // Inputs disagree.
938                                 this_output_width = 0;
939                                 this_output_height = 0;
940                         }
941                 }
942                 if (node->effect->changes_output_size()) {
943                         // We cannot call get_output_size() before we've done inform_input_size()
944                         // on all inputs.
945                         unsigned real_width, real_height;
946                         node->effect->get_output_size(&real_width, &real_height,
947                                                       &node->output_width, &node->output_height);
948                         assert(node->effect->sets_virtual_output_size() ||
949                                (real_width == node->output_width &&
950                                 real_height == node->output_height));
951                 } else {
952                         node->output_width = this_output_width;
953                         node->output_height = this_output_height;
954                 }
955         }
956 }
957
958 // Note: You should call inform_input_sizes() before this, as the last effect's
959 // desired output size might change based on the inputs.
960 void EffectChain::find_output_size(Phase *phase)
961 {
962         Node *output_node = phase->effects.back();
963
964         // If the last effect explicitly sets an output size, use that.
965         if (output_node->effect->changes_output_size()) {
966                 output_node->effect->get_output_size(&phase->output_width, &phase->output_height,
967                                                      &phase->virtual_output_width, &phase->virtual_output_height);
968                 assert(output_node->effect->sets_virtual_output_size() ||
969                        (phase->output_width == phase->virtual_output_width &&
970                         phase->output_height == phase->virtual_output_height));
971                 return;
972         }
973
974         // If all effects have the same size, use that.
975         unsigned output_width = 0, output_height = 0;
976         bool all_inputs_same_size = true;
977
978         for (unsigned i = 0; i < phase->inputs.size(); ++i) {
979                 Phase *input = phase->inputs[i];
980                 assert(input->output_width != 0);
981                 assert(input->output_height != 0);
982                 if (output_width == 0 && output_height == 0) {
983                         output_width = input->virtual_output_width;
984                         output_height = input->virtual_output_height;
985                 } else if (output_width != input->virtual_output_width ||
986                            output_height != input->virtual_output_height) {
987                         all_inputs_same_size = false;
988                 }
989         }
990         for (unsigned i = 0; i < phase->effects.size(); ++i) {
991                 Effect *effect = phase->effects[i]->effect;
992                 if (effect->num_inputs() != 0) {
993                         continue;
994                 }
995
996                 Input *input = static_cast<Input *>(effect);
997                 if (output_width == 0 && output_height == 0) {
998                         output_width = input->get_width();
999                         output_height = input->get_height();
1000                 } else if (output_width != input->get_width() ||
1001                            output_height != input->get_height()) {
1002                         all_inputs_same_size = false;
1003                 }
1004         }
1005
1006         if (all_inputs_same_size) {
1007                 assert(output_width != 0);
1008                 assert(output_height != 0);
1009                 phase->virtual_output_width = phase->output_width = output_width;
1010                 phase->virtual_output_height = phase->output_height = output_height;
1011                 return;
1012         }
1013
1014         // If not, fit all the inputs into the current aspect, and select the largest one. 
1015         output_width = 0;
1016         output_height = 0;
1017         for (unsigned i = 0; i < phase->inputs.size(); ++i) {
1018                 Phase *input = phase->inputs[i];
1019                 assert(input->output_width != 0);
1020                 assert(input->output_height != 0);
1021                 size_rectangle_to_fit(input->output_width, input->output_height, &output_width, &output_height);
1022         }
1023         for (unsigned i = 0; i < phase->effects.size(); ++i) {
1024                 Effect *effect = phase->effects[i]->effect;
1025                 if (effect->num_inputs() != 0) {
1026                         continue;
1027                 }
1028
1029                 Input *input = static_cast<Input *>(effect);
1030                 size_rectangle_to_fit(input->get_width(), input->get_height(), &output_width, &output_height);
1031         }
1032         assert(output_width != 0);
1033         assert(output_height != 0);
1034         phase->virtual_output_width = phase->output_width = output_width;
1035         phase->virtual_output_height = phase->output_height = output_height;
1036 }
1037
1038 void EffectChain::sort_all_nodes_topologically()
1039 {
1040         nodes = topological_sort(nodes);
1041 }
1042
1043 vector<Node *> EffectChain::topological_sort(const vector<Node *> &nodes)
1044 {
1045         set<Node *> nodes_left_to_visit(nodes.begin(), nodes.end());
1046         vector<Node *> sorted_list;
1047         for (unsigned i = 0; i < nodes.size(); ++i) {
1048                 topological_sort_visit_node(nodes[i], &nodes_left_to_visit, &sorted_list);
1049         }
1050         reverse(sorted_list.begin(), sorted_list.end());
1051         return sorted_list;
1052 }
1053
1054 void EffectChain::topological_sort_visit_node(Node *node, set<Node *> *nodes_left_to_visit, vector<Node *> *sorted_list)
1055 {
1056         if (nodes_left_to_visit->count(node) == 0) {
1057                 return;
1058         }
1059         nodes_left_to_visit->erase(node);
1060         for (unsigned i = 0; i < node->outgoing_links.size(); ++i) {
1061                 topological_sort_visit_node(node->outgoing_links[i], nodes_left_to_visit, sorted_list);
1062         }
1063         sorted_list->push_back(node);
1064 }
1065
1066 void EffectChain::find_color_spaces_for_inputs()
1067 {
1068         for (unsigned i = 0; i < nodes.size(); ++i) {
1069                 Node *node = nodes[i];
1070                 if (node->disabled) {
1071                         continue;
1072                 }
1073                 if (node->incoming_links.size() == 0) {
1074                         Input *input = static_cast<Input *>(node->effect);
1075                         node->output_color_space = input->get_color_space();
1076                         node->output_gamma_curve = input->get_gamma_curve();
1077
1078                         Effect::AlphaHandling alpha_handling = input->alpha_handling();
1079                         switch (alpha_handling) {
1080                         case Effect::OUTPUT_BLANK_ALPHA:
1081                                 node->output_alpha_type = ALPHA_BLANK;
1082                                 break;
1083                         case Effect::INPUT_AND_OUTPUT_PREMULTIPLIED_ALPHA:
1084                                 node->output_alpha_type = ALPHA_PREMULTIPLIED;
1085                                 break;
1086                         case Effect::OUTPUT_POSTMULTIPLIED_ALPHA:
1087                                 node->output_alpha_type = ALPHA_POSTMULTIPLIED;
1088                                 break;
1089                         case Effect::INPUT_PREMULTIPLIED_ALPHA_KEEP_BLANK:
1090                         case Effect::DONT_CARE_ALPHA_TYPE:
1091                         default:
1092                                 assert(false);
1093                         }
1094
1095                         if (node->output_alpha_type == ALPHA_PREMULTIPLIED) {
1096                                 assert(node->output_gamma_curve == GAMMA_LINEAR);
1097                         }
1098                 }
1099         }
1100 }
1101
1102 // Propagate gamma and color space information as far as we can in the graph.
1103 // The rules are simple: Anything where all the inputs agree, get that as
1104 // output as well. Anything else keeps having *_INVALID.
1105 void EffectChain::propagate_gamma_and_color_space()
1106 {
1107         // We depend on going through the nodes in order.
1108         sort_all_nodes_topologically();
1109
1110         for (unsigned i = 0; i < nodes.size(); ++i) {
1111                 Node *node = nodes[i];
1112                 if (node->disabled) {
1113                         continue;
1114                 }
1115                 assert(node->incoming_links.size() == node->effect->num_inputs());
1116                 if (node->incoming_links.size() == 0) {
1117                         assert(node->output_color_space != COLORSPACE_INVALID);
1118                         assert(node->output_gamma_curve != GAMMA_INVALID);
1119                         continue;
1120                 }
1121
1122                 Colorspace color_space = node->incoming_links[0]->output_color_space;
1123                 GammaCurve gamma_curve = node->incoming_links[0]->output_gamma_curve;
1124                 for (unsigned j = 1; j < node->incoming_links.size(); ++j) {
1125                         if (node->incoming_links[j]->output_color_space != color_space) {
1126                                 color_space = COLORSPACE_INVALID;
1127                         }
1128                         if (node->incoming_links[j]->output_gamma_curve != gamma_curve) {
1129                                 gamma_curve = GAMMA_INVALID;
1130                         }
1131                 }
1132
1133                 // The conversion effects already have their outputs set correctly,
1134                 // so leave them alone.
1135                 if (node->effect->effect_type_id() != "ColorspaceConversionEffect") {
1136                         node->output_color_space = color_space;
1137                 }               
1138                 if (node->effect->effect_type_id() != "GammaCompressionEffect" &&
1139                     node->effect->effect_type_id() != "GammaExpansionEffect") {
1140                         node->output_gamma_curve = gamma_curve;
1141                 }               
1142         }
1143 }
1144
1145 // Propagate alpha information as far as we can in the graph.
1146 // Similar to propagate_gamma_and_color_space().
1147 void EffectChain::propagate_alpha()
1148 {
1149         // We depend on going through the nodes in order.
1150         sort_all_nodes_topologically();
1151
1152         for (unsigned i = 0; i < nodes.size(); ++i) {
1153                 Node *node = nodes[i];
1154                 if (node->disabled) {
1155                         continue;
1156                 }
1157                 assert(node->incoming_links.size() == node->effect->num_inputs());
1158                 if (node->incoming_links.size() == 0) {
1159                         assert(node->output_alpha_type != ALPHA_INVALID);
1160                         continue;
1161                 }
1162
1163                 // The alpha multiplication/division effects are special cases.
1164                 if (node->effect->effect_type_id() == "AlphaMultiplicationEffect") {
1165                         assert(node->incoming_links.size() == 1);
1166                         assert(node->incoming_links[0]->output_alpha_type == ALPHA_POSTMULTIPLIED);
1167                         node->output_alpha_type = ALPHA_PREMULTIPLIED;
1168                         continue;
1169                 }
1170                 if (node->effect->effect_type_id() == "AlphaDivisionEffect") {
1171                         assert(node->incoming_links.size() == 1);
1172                         assert(node->incoming_links[0]->output_alpha_type == ALPHA_PREMULTIPLIED);
1173                         node->output_alpha_type = ALPHA_POSTMULTIPLIED;
1174                         continue;
1175                 }
1176
1177                 // GammaCompressionEffect and GammaExpansionEffect are also a special case,
1178                 // because they are the only one that _need_ postmultiplied alpha.
1179                 if (node->effect->effect_type_id() == "GammaCompressionEffect" ||
1180                     node->effect->effect_type_id() == "GammaExpansionEffect") {
1181                         assert(node->incoming_links.size() == 1);
1182                         if (node->incoming_links[0]->output_alpha_type == ALPHA_BLANK) {
1183                                 node->output_alpha_type = ALPHA_BLANK;
1184                         } else if (node->incoming_links[0]->output_alpha_type == ALPHA_POSTMULTIPLIED) {
1185                                 node->output_alpha_type = ALPHA_POSTMULTIPLIED;
1186                         } else {
1187                                 node->output_alpha_type = ALPHA_INVALID;
1188                         }
1189                         continue;
1190                 }
1191
1192                 // Only inputs can have unconditional alpha output (OUTPUT_BLANK_ALPHA
1193                 // or OUTPUT_POSTMULTIPLIED_ALPHA), and they have already been
1194                 // taken care of above. Rationale: Even if you could imagine
1195                 // e.g. an effect that took in an image and set alpha=1.0
1196                 // unconditionally, it wouldn't make any sense to have it as
1197                 // e.g. OUTPUT_BLANK_ALPHA, since it wouldn't know whether it
1198                 // got its input pre- or postmultiplied, so it wouldn't know
1199                 // whether to divide away the old alpha or not.
1200                 Effect::AlphaHandling alpha_handling = node->effect->alpha_handling();
1201                 assert(alpha_handling == Effect::INPUT_AND_OUTPUT_PREMULTIPLIED_ALPHA ||
1202                        alpha_handling == Effect::INPUT_PREMULTIPLIED_ALPHA_KEEP_BLANK ||
1203                        alpha_handling == Effect::DONT_CARE_ALPHA_TYPE);
1204
1205                 // If the node has multiple inputs, check that they are all valid and
1206                 // the same.
1207                 bool any_invalid = false;
1208                 bool any_premultiplied = false;
1209                 bool any_postmultiplied = false;
1210
1211                 for (unsigned j = 0; j < node->incoming_links.size(); ++j) {
1212                         switch (node->incoming_links[j]->output_alpha_type) {
1213                         case ALPHA_INVALID:
1214                                 any_invalid = true;
1215                                 break;
1216                         case ALPHA_BLANK:
1217                                 // Blank is good as both pre- and postmultiplied alpha,
1218                                 // so just ignore it.
1219                                 break;
1220                         case ALPHA_PREMULTIPLIED:
1221                                 any_premultiplied = true;
1222                                 break;
1223                         case ALPHA_POSTMULTIPLIED:
1224                                 any_postmultiplied = true;
1225                                 break;
1226                         default:
1227                                 assert(false);
1228                         }
1229                 }
1230
1231                 if (any_invalid) {
1232                         node->output_alpha_type = ALPHA_INVALID;
1233                         continue;
1234                 }
1235
1236                 // Inputs must be of the same type.
1237                 if (any_premultiplied && any_postmultiplied) {
1238                         node->output_alpha_type = ALPHA_INVALID;
1239                         continue;
1240                 }
1241
1242                 if (alpha_handling == Effect::INPUT_AND_OUTPUT_PREMULTIPLIED_ALPHA ||
1243                     alpha_handling == Effect::INPUT_PREMULTIPLIED_ALPHA_KEEP_BLANK) {
1244                         // This combination (requiring premultiplied alpha, but _not_ requiring
1245                         // linear light) is illegal, since the combination of premultiplied alpha
1246                         // and nonlinear inputs is meaningless.
1247                         assert(node->effect->needs_linear_light());
1248
1249                         // If the effect has asked for premultiplied alpha, check that it has got it.
1250                         if (any_postmultiplied) {
1251                                 node->output_alpha_type = ALPHA_INVALID;
1252                         } else if (!any_premultiplied &&
1253                                    alpha_handling == Effect::INPUT_PREMULTIPLIED_ALPHA_KEEP_BLANK) {
1254                                 // Blank input alpha, and the effect preserves blank alpha.
1255                                 node->output_alpha_type = ALPHA_BLANK;
1256                         } else {
1257                                 node->output_alpha_type = ALPHA_PREMULTIPLIED;
1258                         }
1259                 } else {
1260                         // OK, all inputs are the same, and this effect is not going
1261                         // to change it.
1262                         assert(alpha_handling == Effect::DONT_CARE_ALPHA_TYPE);
1263                         if (any_premultiplied) {
1264                                 node->output_alpha_type = ALPHA_PREMULTIPLIED;
1265                         } else if (any_postmultiplied) {
1266                                 node->output_alpha_type = ALPHA_POSTMULTIPLIED;
1267                         } else {
1268                                 node->output_alpha_type = ALPHA_BLANK;
1269                         }
1270                 }
1271         }
1272 }
1273
1274 bool EffectChain::node_needs_colorspace_fix(Node *node)
1275 {
1276         if (node->disabled) {
1277                 return false;
1278         }
1279         if (node->effect->num_inputs() == 0) {
1280                 return false;
1281         }
1282
1283         // propagate_gamma_and_color_space() has already set our output
1284         // to COLORSPACE_INVALID if the inputs differ, so we can rely on that.
1285         if (node->output_color_space == COLORSPACE_INVALID) {
1286                 return true;
1287         }
1288         return (node->effect->needs_srgb_primaries() && node->output_color_space != COLORSPACE_sRGB);
1289 }
1290
1291 // Fix up color spaces so that there are no COLORSPACE_INVALID nodes left in
1292 // the graph. Our strategy is not always optimal, but quite simple:
1293 // Find an effect that's as early as possible where the inputs are of
1294 // unacceptable colorspaces (that is, either different, or, if the effect only
1295 // wants sRGB, not sRGB.) Add appropriate conversions on all its inputs,
1296 // propagate the information anew, and repeat until there are no more such
1297 // effects.
1298 void EffectChain::fix_internal_color_spaces()
1299 {
1300         unsigned colorspace_propagation_pass = 0;
1301         bool found_any;
1302         do {
1303                 found_any = false;
1304                 for (unsigned i = 0; i < nodes.size(); ++i) {
1305                         Node *node = nodes[i];
1306                         if (!node_needs_colorspace_fix(node)) {
1307                                 continue;
1308                         }
1309
1310                         // Go through each input that is not sRGB, and insert
1311                         // a colorspace conversion after it.
1312                         for (unsigned j = 0; j < node->incoming_links.size(); ++j) {
1313                                 Node *input = node->incoming_links[j];
1314                                 assert(input->output_color_space != COLORSPACE_INVALID);
1315                                 if (input->output_color_space == COLORSPACE_sRGB) {
1316                                         continue;
1317                                 }
1318                                 Node *conversion = add_node(new ColorspaceConversionEffect());
1319                                 CHECK(conversion->effect->set_int("source_space", input->output_color_space));
1320                                 CHECK(conversion->effect->set_int("destination_space", COLORSPACE_sRGB));
1321                                 conversion->output_color_space = COLORSPACE_sRGB;
1322                                 replace_sender(input, conversion);
1323                                 connect_nodes(input, conversion);
1324                         }
1325
1326                         // Re-sort topologically, and propagate the new information.
1327                         propagate_gamma_and_color_space();
1328                         
1329                         found_any = true;
1330                         break;
1331                 }
1332         
1333                 char filename[256];
1334                 sprintf(filename, "step5-colorspacefix-iter%u.dot", ++colorspace_propagation_pass);
1335                 output_dot(filename);
1336                 assert(colorspace_propagation_pass < 100);
1337         } while (found_any);
1338
1339         for (unsigned i = 0; i < nodes.size(); ++i) {
1340                 Node *node = nodes[i];
1341                 if (node->disabled) {
1342                         continue;
1343                 }
1344                 assert(node->output_color_space != COLORSPACE_INVALID);
1345         }
1346 }
1347
1348 bool EffectChain::node_needs_alpha_fix(Node *node)
1349 {
1350         if (node->disabled) {
1351                 return false;
1352         }
1353
1354         // propagate_alpha() has already set our output to ALPHA_INVALID if the
1355         // inputs differ or we are otherwise in mismatch, so we can rely on that.
1356         return (node->output_alpha_type == ALPHA_INVALID);
1357 }
1358
1359 // Fix up alpha so that there are no ALPHA_INVALID nodes left in
1360 // the graph. Similar to fix_internal_color_spaces().
1361 void EffectChain::fix_internal_alpha(unsigned step)
1362 {
1363         unsigned alpha_propagation_pass = 0;
1364         bool found_any;
1365         do {
1366                 found_any = false;
1367                 for (unsigned i = 0; i < nodes.size(); ++i) {
1368                         Node *node = nodes[i];
1369                         if (!node_needs_alpha_fix(node)) {
1370                                 continue;
1371                         }
1372
1373                         // If we need to fix up GammaExpansionEffect, then clearly something
1374                         // is wrong, since the combination of premultiplied alpha and nonlinear inputs
1375                         // is meaningless.
1376                         assert(node->effect->effect_type_id() != "GammaExpansionEffect");
1377
1378                         AlphaType desired_type = ALPHA_PREMULTIPLIED;
1379
1380                         // GammaCompressionEffect is special; it needs postmultiplied alpha.
1381                         if (node->effect->effect_type_id() == "GammaCompressionEffect") {
1382                                 assert(node->incoming_links.size() == 1);
1383                                 assert(node->incoming_links[0]->output_alpha_type == ALPHA_PREMULTIPLIED);
1384                                 desired_type = ALPHA_POSTMULTIPLIED;
1385                         }
1386
1387                         // Go through each input that is not premultiplied alpha, and insert
1388                         // a conversion before it.
1389                         for (unsigned j = 0; j < node->incoming_links.size(); ++j) {
1390                                 Node *input = node->incoming_links[j];
1391                                 assert(input->output_alpha_type != ALPHA_INVALID);
1392                                 if (input->output_alpha_type == desired_type ||
1393                                     input->output_alpha_type == ALPHA_BLANK) {
1394                                         continue;
1395                                 }
1396                                 Node *conversion;
1397                                 if (desired_type == ALPHA_PREMULTIPLIED) {
1398                                         conversion = add_node(new AlphaMultiplicationEffect());
1399                                 } else {
1400                                         conversion = add_node(new AlphaDivisionEffect());
1401                                 }
1402                                 conversion->output_alpha_type = desired_type;
1403                                 replace_sender(input, conversion);
1404                                 connect_nodes(input, conversion);
1405                         }
1406
1407                         // Re-sort topologically, and propagate the new information.
1408                         propagate_gamma_and_color_space();
1409                         propagate_alpha();
1410                         
1411                         found_any = true;
1412                         break;
1413                 }
1414         
1415                 char filename[256];
1416                 sprintf(filename, "step%u-alphafix-iter%u.dot", step, ++alpha_propagation_pass);
1417                 output_dot(filename);
1418                 assert(alpha_propagation_pass < 100);
1419         } while (found_any);
1420
1421         for (unsigned i = 0; i < nodes.size(); ++i) {
1422                 Node *node = nodes[i];
1423                 if (node->disabled) {
1424                         continue;
1425                 }
1426                 assert(node->output_alpha_type != ALPHA_INVALID);
1427         }
1428 }
1429
1430 // Make so that the output is in the desired color space.
1431 void EffectChain::fix_output_color_space()
1432 {
1433         Node *output = find_output_node();
1434         if (output->output_color_space != output_format.color_space) {
1435                 Node *conversion = add_node(new ColorspaceConversionEffect());
1436                 CHECK(conversion->effect->set_int("source_space", output->output_color_space));
1437                 CHECK(conversion->effect->set_int("destination_space", output_format.color_space));
1438                 conversion->output_color_space = output_format.color_space;
1439                 connect_nodes(output, conversion);
1440                 propagate_alpha();
1441                 propagate_gamma_and_color_space();
1442         }
1443 }
1444
1445 // Make so that the output is in the desired pre-/postmultiplication alpha state.
1446 void EffectChain::fix_output_alpha()
1447 {
1448         Node *output = find_output_node();
1449         assert(output->output_alpha_type != ALPHA_INVALID);
1450         if (output->output_alpha_type == ALPHA_BLANK) {
1451                 // No alpha output, so we don't care.
1452                 return;
1453         }
1454         if (output->output_alpha_type == ALPHA_PREMULTIPLIED &&
1455             output_alpha_format == OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED) {
1456                 Node *conversion = add_node(new AlphaDivisionEffect());
1457                 connect_nodes(output, conversion);
1458                 propagate_alpha();
1459                 propagate_gamma_and_color_space();
1460         }
1461         if (output->output_alpha_type == ALPHA_POSTMULTIPLIED &&
1462             output_alpha_format == OUTPUT_ALPHA_FORMAT_PREMULTIPLIED) {
1463                 Node *conversion = add_node(new AlphaMultiplicationEffect());
1464                 connect_nodes(output, conversion);
1465                 propagate_alpha();
1466                 propagate_gamma_and_color_space();
1467         }
1468 }
1469
1470 bool EffectChain::node_needs_gamma_fix(Node *node)
1471 {
1472         if (node->disabled) {
1473                 return false;
1474         }
1475
1476         // Small hack since the output is not an explicit node:
1477         // If we are the last node and our output is in the wrong
1478         // space compared to EffectChain's output, we need to fix it.
1479         // This will only take us to linear, but fix_output_gamma()
1480         // will come and take us to the desired output gamma
1481         // if it is needed.
1482         //
1483         // This needs to be before everything else, since it could
1484         // even apply to inputs (if they are the only effect).
1485         if (node->outgoing_links.empty() &&
1486             node->output_gamma_curve != output_format.gamma_curve &&
1487             node->output_gamma_curve != GAMMA_LINEAR) {
1488                 return true;
1489         }
1490
1491         if (node->effect->num_inputs() == 0) {
1492                 return false;
1493         }
1494
1495         // propagate_gamma_and_color_space() has already set our output
1496         // to GAMMA_INVALID if the inputs differ, so we can rely on that,
1497         // except for GammaCompressionEffect.
1498         if (node->output_gamma_curve == GAMMA_INVALID) {
1499                 return true;
1500         }
1501         if (node->effect->effect_type_id() == "GammaCompressionEffect") {
1502                 assert(node->incoming_links.size() == 1);
1503                 return node->incoming_links[0]->output_gamma_curve != GAMMA_LINEAR;
1504         }
1505
1506         return (node->effect->needs_linear_light() && node->output_gamma_curve != GAMMA_LINEAR);
1507 }
1508
1509 // Very similar to fix_internal_color_spaces(), but for gamma.
1510 // There is one difference, though; before we start adding conversion nodes,
1511 // we see if we can get anything out of asking the sources to deliver
1512 // linear gamma directly. fix_internal_gamma_by_asking_inputs()
1513 // does that part, while fix_internal_gamma_by_inserting_nodes()
1514 // inserts nodes as needed afterwards.
1515 void EffectChain::fix_internal_gamma_by_asking_inputs(unsigned step)
1516 {
1517         unsigned gamma_propagation_pass = 0;
1518         bool found_any;
1519         do {
1520                 found_any = false;
1521                 for (unsigned i = 0; i < nodes.size(); ++i) {
1522                         Node *node = nodes[i];
1523                         if (!node_needs_gamma_fix(node)) {
1524                                 continue;
1525                         }
1526
1527                         // See if all inputs can give us linear gamma. If not, leave it.
1528                         vector<Node *> nonlinear_inputs;
1529                         find_all_nonlinear_inputs(node, &nonlinear_inputs);
1530                         assert(!nonlinear_inputs.empty());
1531
1532                         bool all_ok = true;
1533                         for (unsigned i = 0; i < nonlinear_inputs.size(); ++i) {
1534                                 Input *input = static_cast<Input *>(nonlinear_inputs[i]->effect);
1535                                 all_ok &= input->can_output_linear_gamma();
1536                         }
1537
1538                         if (!all_ok) {
1539                                 continue;
1540                         }
1541
1542                         for (unsigned i = 0; i < nonlinear_inputs.size(); ++i) {
1543                                 CHECK(nonlinear_inputs[i]->effect->set_int("output_linear_gamma", 1));
1544                                 nonlinear_inputs[i]->output_gamma_curve = GAMMA_LINEAR;
1545                         }
1546
1547                         // Re-sort topologically, and propagate the new information.
1548                         propagate_gamma_and_color_space();
1549                         
1550                         found_any = true;
1551                         break;
1552                 }
1553         
1554                 char filename[256];
1555                 sprintf(filename, "step%u-gammafix-iter%u.dot", step, ++gamma_propagation_pass);
1556                 output_dot(filename);
1557                 assert(gamma_propagation_pass < 100);
1558         } while (found_any);
1559 }
1560
1561 void EffectChain::fix_internal_gamma_by_inserting_nodes(unsigned step)
1562 {
1563         unsigned gamma_propagation_pass = 0;
1564         bool found_any;
1565         do {
1566                 found_any = false;
1567                 for (unsigned i = 0; i < nodes.size(); ++i) {
1568                         Node *node = nodes[i];
1569                         if (!node_needs_gamma_fix(node)) {
1570                                 continue;
1571                         }
1572
1573                         // Special case: We could be an input and still be asked to
1574                         // fix our gamma; if so, we should be the only node
1575                         // (as node_needs_gamma_fix() would only return true in
1576                         // for an input in that case). That means we should insert
1577                         // a conversion node _after_ ourselves.
1578                         if (node->incoming_links.empty()) {
1579                                 assert(node->outgoing_links.empty());
1580                                 Node *conversion = add_node(new GammaExpansionEffect());
1581                                 CHECK(conversion->effect->set_int("source_curve", node->output_gamma_curve));
1582                                 conversion->output_gamma_curve = GAMMA_LINEAR;
1583                                 connect_nodes(node, conversion);
1584                         }
1585
1586                         // If not, go through each input that is not linear gamma,
1587                         // and insert a gamma conversion after it.
1588                         for (unsigned j = 0; j < node->incoming_links.size(); ++j) {
1589                                 Node *input = node->incoming_links[j];
1590                                 assert(input->output_gamma_curve != GAMMA_INVALID);
1591                                 if (input->output_gamma_curve == GAMMA_LINEAR) {
1592                                         continue;
1593                                 }
1594                                 Node *conversion = add_node(new GammaExpansionEffect());
1595                                 CHECK(conversion->effect->set_int("source_curve", input->output_gamma_curve));
1596                                 conversion->output_gamma_curve = GAMMA_LINEAR;
1597                                 replace_sender(input, conversion);
1598                                 connect_nodes(input, conversion);
1599                         }
1600
1601                         // Re-sort topologically, and propagate the new information.
1602                         propagate_alpha();
1603                         propagate_gamma_and_color_space();
1604                         
1605                         found_any = true;
1606                         break;
1607                 }
1608         
1609                 char filename[256];
1610                 sprintf(filename, "step%u-gammafix-iter%u.dot", step, ++gamma_propagation_pass);
1611                 output_dot(filename);
1612                 assert(gamma_propagation_pass < 100);
1613         } while (found_any);
1614
1615         for (unsigned i = 0; i < nodes.size(); ++i) {
1616                 Node *node = nodes[i];
1617                 if (node->disabled) {
1618                         continue;
1619                 }
1620                 assert(node->output_gamma_curve != GAMMA_INVALID);
1621         }
1622 }
1623
1624 // Make so that the output is in the desired gamma.
1625 // Note that this assumes linear input gamma, so it might create the need
1626 // for another pass of fix_internal_gamma().
1627 void EffectChain::fix_output_gamma()
1628 {
1629         Node *output = find_output_node();
1630         if (output->output_gamma_curve != output_format.gamma_curve) {
1631                 Node *conversion = add_node(new GammaCompressionEffect());
1632                 CHECK(conversion->effect->set_int("destination_curve", output_format.gamma_curve));
1633                 conversion->output_gamma_curve = output_format.gamma_curve;
1634                 connect_nodes(output, conversion);
1635         }
1636 }
1637
1638 // If the user has requested Y'CbCr output, we need to do this conversion
1639 // _after_ GammaCompressionEffect etc., but before dither (see below).
1640 // This is because Y'CbCr, with the exception of a special optional mode
1641 // in Rec. 2020 (which we currently don't support), is defined to work on
1642 // gamma-encoded data.
1643 void EffectChain::add_ycbcr_conversion_if_needed()
1644 {
1645         assert(output_color_rgba || num_output_color_ycbcr > 0);
1646         if (num_output_color_ycbcr == 0) {
1647                 return;
1648         }
1649         Node *output = find_output_node();
1650         ycbcr_conversion_effect_node = add_node(new YCbCrConversionEffect(output_ycbcr_format, output_ycbcr_type));
1651         connect_nodes(output, ycbcr_conversion_effect_node);
1652 }
1653         
1654 // If the user has requested dither, add a DitherEffect right at the end
1655 // (after GammaCompressionEffect etc.). This needs to be done after everything else,
1656 // since dither is about the only effect that can _not_ be done in linear space.
1657 void EffectChain::add_dither_if_needed()
1658 {
1659         if (num_dither_bits == 0) {
1660                 return;
1661         }
1662         Node *output = find_output_node();
1663         Node *dither = add_node(new DitherEffect());
1664         CHECK(dither->effect->set_int("num_bits", num_dither_bits));
1665         connect_nodes(output, dither);
1666
1667         dither_effect = dither->effect;
1668 }
1669
1670 // Find the output node. This is, simply, one that has no outgoing links.
1671 // If there are multiple ones, the graph is malformed (we do not support
1672 // multiple outputs right now).
1673 Node *EffectChain::find_output_node()
1674 {
1675         vector<Node *> output_nodes;
1676         for (unsigned i = 0; i < nodes.size(); ++i) {
1677                 Node *node = nodes[i];
1678                 if (node->disabled) {
1679                         continue;
1680                 }
1681                 if (node->outgoing_links.empty()) {
1682                         output_nodes.push_back(node);
1683                 }
1684         }
1685         assert(output_nodes.size() == 1);
1686         return output_nodes[0];
1687 }
1688
1689 void EffectChain::finalize()
1690 {
1691         // Output the graph as it is before we do any conversions on it.
1692         output_dot("step0-start.dot");
1693
1694         // Give each effect in turn a chance to rewrite its own part of the graph.
1695         // Note that if more effects are added as part of this, they will be
1696         // picked up as part of the same for loop, since they are added at the end.
1697         for (unsigned i = 0; i < nodes.size(); ++i) {
1698                 nodes[i]->effect->rewrite_graph(this, nodes[i]);
1699         }
1700         output_dot("step1-rewritten.dot");
1701
1702         find_color_spaces_for_inputs();
1703         output_dot("step2-input-colorspace.dot");
1704
1705         propagate_alpha();
1706         output_dot("step3-propagated-alpha.dot");
1707
1708         propagate_gamma_and_color_space();
1709         output_dot("step4-propagated-all.dot");
1710
1711         fix_internal_color_spaces();
1712         fix_internal_alpha(6);
1713         fix_output_color_space();
1714         output_dot("step7-output-colorspacefix.dot");
1715         fix_output_alpha();
1716         output_dot("step8-output-alphafix.dot");
1717
1718         // Note that we need to fix gamma after colorspace conversion,
1719         // because colorspace conversions might create needs for gamma conversions.
1720         // Also, we need to run an extra pass of fix_internal_gamma() after 
1721         // fixing the output gamma, as we only have conversions to/from linear,
1722         // and fix_internal_alpha() since GammaCompressionEffect needs
1723         // postmultiplied input.
1724         fix_internal_gamma_by_asking_inputs(9);
1725         fix_internal_gamma_by_inserting_nodes(10);
1726         fix_output_gamma();
1727         output_dot("step11-output-gammafix.dot");
1728         propagate_alpha();
1729         output_dot("step12-output-alpha-propagated.dot");
1730         fix_internal_alpha(13);
1731         output_dot("step14-output-alpha-fixed.dot");
1732         fix_internal_gamma_by_asking_inputs(15);
1733         fix_internal_gamma_by_inserting_nodes(16);
1734
1735         output_dot("step17-before-ycbcr.dot");
1736         add_ycbcr_conversion_if_needed();
1737
1738         output_dot("step18-before-dither.dot");
1739         add_dither_if_needed();
1740
1741         output_dot("step19-final.dot");
1742         
1743         // Construct all needed GLSL programs, starting at the output.
1744         // We need to keep track of which effects have already been computed,
1745         // as an effect with multiple users could otherwise be calculated
1746         // multiple times.
1747         map<Node *, Phase *> completed_effects;
1748         construct_phase(find_output_node(), &completed_effects);
1749
1750         output_dot("step20-split-to-phases.dot");
1751
1752         assert(phases[0]->inputs.empty());
1753         
1754         finalized = true;
1755 }
1756
1757 void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height)
1758 {
1759         assert(finalized);
1760
1761         // This needs to be set anew, in case we are coming from a different context
1762         // from when we initialized.
1763         check_error();
1764         glDisable(GL_DITHER);
1765         check_error();
1766
1767         const bool final_srgb = glIsEnabled(GL_FRAMEBUFFER_SRGB);
1768         check_error();
1769         bool current_srgb = final_srgb;
1770
1771         // Save original viewport.
1772         GLuint x = 0, y = 0;
1773
1774         if (width == 0 && height == 0) {
1775                 GLint viewport[4];
1776                 glGetIntegerv(GL_VIEWPORT, viewport);
1777                 x = viewport[0];
1778                 y = viewport[1];
1779                 width = viewport[2];
1780                 height = viewport[3];
1781         }
1782
1783         // Basic state.
1784         check_error();
1785         glDisable(GL_BLEND);
1786         check_error();
1787         glDisable(GL_DEPTH_TEST);
1788         check_error();
1789         glDepthMask(GL_FALSE);
1790         check_error();
1791
1792         // Generate a VAO that will be used during the entire execution,
1793         // and bind the VBO, since it contains all the data.
1794         GLuint vao;
1795         glGenVertexArrays(1, &vao);
1796         check_error();
1797         glBindVertexArray(vao);
1798         check_error();
1799         glBindBuffer(GL_ARRAY_BUFFER, vbo);
1800         check_error();
1801         set<GLint> bound_attribute_indices;
1802
1803         set<Phase *> generated_mipmaps;
1804
1805         // We choose the simplest option of having one texture per output,
1806         // since otherwise this turns into an (albeit simple) register allocation problem.
1807         map<Phase *, GLuint> output_textures;
1808
1809         for (unsigned phase_num = 0; phase_num < phases.size(); ++phase_num) {
1810                 Phase *phase = phases[phase_num];
1811
1812                 if (do_phase_timing) {
1813                         GLuint timer_query_object;
1814                         if (phase->timer_query_objects_free.empty()) {
1815                                 glGenQueries(1, &timer_query_object);
1816                         } else {
1817                                 timer_query_object = phase->timer_query_objects_free.front();
1818                                 phase->timer_query_objects_free.pop_front();
1819                         }
1820                         glBeginQuery(GL_TIME_ELAPSED, timer_query_object);
1821                         phase->timer_query_objects_running.push_back(timer_query_object);
1822                 }
1823                 if (phase_num == phases.size() - 1) {
1824                         // Last phase goes to the output the user specified.
1825                         glBindFramebuffer(GL_FRAMEBUFFER, dest_fbo);
1826                         check_error();
1827                         GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
1828                         assert(status == GL_FRAMEBUFFER_COMPLETE);
1829                         glViewport(x, y, width, height);
1830                         if (dither_effect != NULL) {
1831                                 CHECK(dither_effect->set_int("output_width", width));
1832                                 CHECK(dither_effect->set_int("output_height", height));
1833                         }
1834                 }
1835                 bool last_phase = (phase_num == phases.size() - 1);
1836
1837                 // Enable sRGB rendering for intermediates in case we are
1838                 // rendering to an sRGB format.
1839                 bool needs_srgb = last_phase ? final_srgb : true;
1840                 if (needs_srgb && !current_srgb) {
1841                         glEnable(GL_FRAMEBUFFER_SRGB);
1842                         check_error();
1843                         current_srgb = true;
1844                 } else if (!needs_srgb && current_srgb) {
1845                         glDisable(GL_FRAMEBUFFER_SRGB);
1846                         check_error();
1847                         current_srgb = true;
1848                 }
1849
1850                 execute_phase(phase, last_phase, &bound_attribute_indices, &output_textures, &generated_mipmaps);
1851                 if (do_phase_timing) {
1852                         glEndQuery(GL_TIME_ELAPSED);
1853                 }
1854         }
1855
1856         for (map<Phase *, GLuint>::const_iterator texture_it = output_textures.begin();
1857              texture_it != output_textures.end();
1858              ++texture_it) {
1859                 resource_pool->release_2d_texture(texture_it->second);
1860         }
1861
1862         glBindFramebuffer(GL_FRAMEBUFFER, 0);
1863         check_error();
1864         glUseProgram(0);
1865         check_error();
1866
1867         glBindBuffer(GL_ARRAY_BUFFER, 0);
1868         check_error();
1869         glBindVertexArray(0);
1870         check_error();
1871         glDeleteVertexArrays(1, &vao);
1872         check_error();
1873
1874         if (do_phase_timing) {
1875                 // Get back the timer queries.
1876                 for (unsigned phase_num = 0; phase_num < phases.size(); ++phase_num) {
1877                         Phase *phase = phases[phase_num];
1878                         for (std::list<GLuint>::iterator timer_it = phase->timer_query_objects_running.begin();
1879                              timer_it != phase->timer_query_objects_running.end(); ) {
1880                                 GLint timer_query_object = *timer_it;
1881                                 GLint available;
1882                                 glGetQueryObjectiv(timer_query_object, GL_QUERY_RESULT_AVAILABLE, &available);
1883                                 if (available) {
1884                                         GLuint64 time_elapsed;
1885                                         glGetQueryObjectui64v(timer_query_object, GL_QUERY_RESULT, &time_elapsed);
1886                                         phase->time_elapsed_ns += time_elapsed;
1887                                         ++phase->num_measured_iterations;
1888                                         phase->timer_query_objects_free.push_back(timer_query_object);
1889                                         phase->timer_query_objects_running.erase(timer_it++);
1890                                 } else {
1891                                         ++timer_it;
1892                                 }
1893                         }
1894                 }
1895         }
1896 }
1897
1898 void EffectChain::enable_phase_timing(bool enable)
1899 {
1900         if (enable) {
1901                 assert(movit_timer_queries_supported);
1902         }
1903         this->do_phase_timing = enable;
1904 }
1905
1906 void EffectChain::reset_phase_timing()
1907 {
1908         for (unsigned phase_num = 0; phase_num < phases.size(); ++phase_num) {
1909                 Phase *phase = phases[phase_num];
1910                 phase->time_elapsed_ns = 0;
1911                 phase->num_measured_iterations = 0;
1912         }
1913 }
1914
1915 void EffectChain::print_phase_timing()
1916 {
1917         double total_time_ms = 0.0;
1918         for (unsigned phase_num = 0; phase_num < phases.size(); ++phase_num) {
1919                 Phase *phase = phases[phase_num];
1920                 double avg_time_ms = phase->time_elapsed_ns * 1e-6 / phase->num_measured_iterations;
1921                 printf("Phase %d: %5.1f ms  [", phase_num, avg_time_ms);
1922                 for (unsigned effect_num = 0; effect_num < phase->effects.size(); ++effect_num) {
1923                         if (effect_num != 0) {
1924                                 printf(", ");
1925                         }
1926                         printf("%s", phase->effects[effect_num]->effect->effect_type_id().c_str());
1927                 }
1928                 printf("]\n");
1929                 total_time_ms += avg_time_ms;
1930         }
1931         printf("Total:   %5.1f ms\n", total_time_ms);
1932 }
1933
1934 void EffectChain::execute_phase(Phase *phase, bool last_phase,
1935                                 set<GLint> *bound_attribute_indices,
1936                                 map<Phase *, GLuint> *output_textures,
1937                                 set<Phase *> *generated_mipmaps)
1938 {
1939         GLuint fbo = 0;
1940
1941         // Find a texture for this phase.
1942         inform_input_sizes(phase);
1943         if (!last_phase) {
1944                 find_output_size(phase);
1945
1946                 GLuint tex_num = resource_pool->create_2d_texture(intermediate_format, phase->output_width, phase->output_height);
1947                 output_textures->insert(make_pair(phase, tex_num));
1948         }
1949
1950         // Set up RTT inputs for this phase.
1951         for (unsigned sampler = 0; sampler < phase->inputs.size(); ++sampler) {
1952                 glActiveTexture(GL_TEXTURE0 + sampler);
1953                 Phase *input = phase->inputs[sampler];
1954                 input->output_node->bound_sampler_num = sampler;
1955                 glBindTexture(GL_TEXTURE_2D, (*output_textures)[input]);
1956                 check_error();
1957                 if (phase->input_needs_mipmaps && generated_mipmaps->count(input) == 0) {
1958                         glGenerateMipmap(GL_TEXTURE_2D);
1959                         check_error();
1960                         generated_mipmaps->insert(input);
1961                 }
1962                 setup_rtt_sampler(sampler, phase->input_needs_mipmaps);
1963                 phase->input_samplers[sampler] = sampler;  // Bind the sampler to the right uniform.
1964         }
1965
1966         // And now the output. (Already set up for us if it is the last phase.)
1967         if (!last_phase) {
1968                 fbo = resource_pool->create_fbo((*output_textures)[phase]);
1969                 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1970                 glViewport(0, 0, phase->output_width, phase->output_height);
1971         }
1972
1973         GLuint instance_program_num = resource_pool->use_glsl_program(phase->glsl_program_num);
1974         check_error();
1975
1976         // Give the required parameters to all the effects.
1977         unsigned sampler_num = phase->inputs.size();
1978         for (unsigned i = 0; i < phase->effects.size(); ++i) {
1979                 Node *node = phase->effects[i];
1980                 unsigned old_sampler_num = sampler_num;
1981                 node->effect->set_gl_state(instance_program_num, phase->effect_ids[node], &sampler_num);
1982                 check_error();
1983
1984                 if (node->effect->is_single_texture()) {
1985                         assert(sampler_num - old_sampler_num == 1);
1986                         node->bound_sampler_num = old_sampler_num;
1987                 } else {
1988                         node->bound_sampler_num = -1;
1989                 }
1990         }
1991
1992         // Uniforms need to come after set_gl_state(), since they can be updated
1993         // from there.
1994         setup_uniforms(phase);
1995
1996         // Clean up old attributes if they are no longer needed.
1997         for (set<GLint>::iterator attr_it = bound_attribute_indices->begin();
1998              attr_it != bound_attribute_indices->end(); ) {
1999                 if (phase->attribute_indexes.count(*attr_it) == 0) {
2000                         glDisableVertexAttribArray(*attr_it);
2001                         check_error();
2002                         bound_attribute_indices->erase(attr_it++);
2003                 } else {
2004                         ++attr_it;
2005                 }
2006         }
2007
2008         // Set up the new attributes, if needed.
2009         for (set<GLint>::iterator attr_it = phase->attribute_indexes.begin();
2010              attr_it != phase->attribute_indexes.end();
2011              ++attr_it) {
2012                 if (bound_attribute_indices->count(*attr_it) == 0) {
2013                         glEnableVertexAttribArray(*attr_it);
2014                         check_error();
2015                         glVertexAttribPointer(*attr_it, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
2016                         check_error();
2017                         bound_attribute_indices->insert(*attr_it);
2018                 }
2019         }
2020
2021         glDrawArrays(GL_TRIANGLES, 0, 3);
2022         check_error();
2023         
2024         for (unsigned i = 0; i < phase->effects.size(); ++i) {
2025                 Node *node = phase->effects[i];
2026                 node->effect->clear_gl_state();
2027         }
2028
2029         resource_pool->unuse_glsl_program(instance_program_num);
2030
2031         if (!last_phase) {
2032                 resource_pool->release_fbo(fbo);
2033         }
2034 }
2035
2036 void EffectChain::setup_uniforms(Phase *phase)
2037 {
2038         // TODO: Use UBO blocks.
2039         for (size_t i = 0; i < phase->uniforms_sampler2d.size(); ++i) {
2040                 const Uniform<int> &uniform = phase->uniforms_sampler2d[i];
2041                 if (uniform.location != -1) {
2042                         glUniform1iv(uniform.location, uniform.num_values, uniform.value);
2043                 }
2044         }
2045         for (size_t i = 0; i < phase->uniforms_bool.size(); ++i) {
2046                 const Uniform<bool> &uniform = phase->uniforms_bool[i];
2047                 assert(uniform.num_values == 1);
2048                 if (uniform.location != -1) {
2049                         glUniform1i(uniform.location, *uniform.value);
2050                 }
2051         }
2052         for (size_t i = 0; i < phase->uniforms_int.size(); ++i) {
2053                 const Uniform<int> &uniform = phase->uniforms_int[i];
2054                 if (uniform.location != -1) {
2055                         glUniform1iv(uniform.location, uniform.num_values, uniform.value);
2056                 }
2057         }
2058         for (size_t i = 0; i < phase->uniforms_float.size(); ++i) {
2059                 const Uniform<float> &uniform = phase->uniforms_float[i];
2060                 if (uniform.location != -1) {
2061                         glUniform1fv(uniform.location, uniform.num_values, uniform.value);
2062                 }
2063         }
2064         for (size_t i = 0; i < phase->uniforms_vec2.size(); ++i) {
2065                 const Uniform<float> &uniform = phase->uniforms_vec2[i];
2066                 if (uniform.location != -1) {
2067                         glUniform2fv(uniform.location, uniform.num_values, uniform.value);
2068                 }
2069         }
2070         for (size_t i = 0; i < phase->uniforms_vec3.size(); ++i) {
2071                 const Uniform<float> &uniform = phase->uniforms_vec3[i];
2072                 if (uniform.location != -1) {
2073                         glUniform3fv(uniform.location, uniform.num_values, uniform.value);
2074                 }
2075         }
2076         for (size_t i = 0; i < phase->uniforms_vec4.size(); ++i) {
2077                 const Uniform<float> &uniform = phase->uniforms_vec4[i];
2078                 if (uniform.location != -1) {
2079                         glUniform4fv(uniform.location, uniform.num_values, uniform.value);
2080                 }
2081         }
2082         for (size_t i = 0; i < phase->uniforms_mat3.size(); ++i) {
2083                 const Uniform<Matrix3d> &uniform = phase->uniforms_mat3[i];
2084                 assert(uniform.num_values == 1);
2085                 if (uniform.location != -1) {
2086                         // Convert to float (GLSL has no double matrices).
2087                         float matrixf[9];
2088                         for (unsigned y = 0; y < 3; ++y) {
2089                                 for (unsigned x = 0; x < 3; ++x) {
2090                                         matrixf[y + x * 3] = (*uniform.value)(y, x);
2091                                 }
2092                         }
2093                         glUniformMatrix3fv(uniform.location, 1, GL_FALSE, matrixf);
2094                 }
2095         }
2096 }
2097
2098 void EffectChain::setup_rtt_sampler(int sampler_num, bool use_mipmaps)
2099 {
2100         glActiveTexture(GL_TEXTURE0 + sampler_num);
2101         check_error();
2102         if (use_mipmaps) {
2103                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
2104                 check_error();
2105         } else {
2106                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2107                 check_error();
2108         }
2109         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2110         check_error();
2111         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2112         check_error();
2113 }
2114
2115 }  // namespace movit