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