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