+
+ // If we're bouncing to a temporary texture, signal transformation if desired.
+ if (!phase->output_node->outgoing_links.empty()) {
+ if (intermediate_transformation == SQUARE_ROOT_FRAMEBUFFER_TRANSFORMATION &&
+ phase->output_node->output_gamma_curve == GAMMA_LINEAR) {
+ frag_shader += "#define SQUARE_ROOT_TRANSFORMATION 1\n";
+ }
+ }
+
+ if (phase->is_compute_shader) {
+ frag_shader.append(read_file("footer.comp"));
+ phase->compute_shader_node->effect->register_uniform_ivec2("output_size", phase->uniform_output_size);
+ phase->compute_shader_node->effect->register_uniform_vec2("inv_output_size", (float *)&phase->inv_output_size);
+ phase->compute_shader_node->effect->register_uniform_vec2("output_texcoord_adjust", (float *)&phase->output_texcoord_adjust);
+ } else {
+ frag_shader.append(read_file("footer.frag"));
+ }
+
+ // Collect uniforms from all effects and output them. Note that this needs
+ // to happen after output_fragment_shader(), even though the uniforms come
+ // before in the output source, since output_fragment_shader() is allowed
+ // to register new uniforms (e.g. arrays that are of unknown length until
+ // finalization time).
+ // TODO: Make a uniform block for platforms that support it.
+ string frag_shader_uniforms = "";
+ for (unsigned i = 0; i < phase->effects.size(); ++i) {
+ Node *node = phase->effects[i];
+ Effect *effect = node->effect;
+ const string effect_id = phase->effect_ids[make_pair(node, IN_SAME_PHASE)];
+ extract_uniform_declarations(effect->uniforms_image2d, "image2D", effect_id, &phase->uniforms_image2d, &frag_shader_uniforms);
+ extract_uniform_declarations(effect->uniforms_sampler2d, "sampler2D", effect_id, &phase->uniforms_sampler2d, &frag_shader_uniforms);
+ extract_uniform_declarations(effect->uniforms_bool, "bool", effect_id, &phase->uniforms_bool, &frag_shader_uniforms);
+ extract_uniform_declarations(effect->uniforms_int, "int", effect_id, &phase->uniforms_int, &frag_shader_uniforms);
+ extract_uniform_declarations(effect->uniforms_ivec2, "ivec2", effect_id, &phase->uniforms_ivec2, &frag_shader_uniforms);
+ extract_uniform_declarations(effect->uniforms_float, "float", effect_id, &phase->uniforms_float, &frag_shader_uniforms);
+ extract_uniform_declarations(effect->uniforms_vec2, "vec2", effect_id, &phase->uniforms_vec2, &frag_shader_uniforms);
+ extract_uniform_declarations(effect->uniforms_vec3, "vec3", effect_id, &phase->uniforms_vec3, &frag_shader_uniforms);
+ extract_uniform_declarations(effect->uniforms_vec4, "vec4", effect_id, &phase->uniforms_vec4, &frag_shader_uniforms);
+ extract_uniform_array_declarations(effect->uniforms_float_array, "float", effect_id, &phase->uniforms_float, &frag_shader_uniforms);
+ extract_uniform_array_declarations(effect->uniforms_vec2_array, "vec2", effect_id, &phase->uniforms_vec2, &frag_shader_uniforms);
+ extract_uniform_array_declarations(effect->uniforms_vec3_array, "vec3", effect_id, &phase->uniforms_vec3, &frag_shader_uniforms);
+ extract_uniform_array_declarations(effect->uniforms_vec4_array, "vec4", effect_id, &phase->uniforms_vec4, &frag_shader_uniforms);
+ extract_uniform_declarations(effect->uniforms_mat3, "mat3", effect_id, &phase->uniforms_mat3, &frag_shader_uniforms);
+ }
+
+ string vert_shader = read_version_dependent_file("vs", "vert");
+
+ // If we're the last phase and need to flip the picture to compensate for
+ // the origin, tell the vertex or compute shader so.
+ bool is_last_phase;
+ if (has_dummy_effect) {
+ is_last_phase = (phase->output_node->outgoing_links.size() == 1 &&
+ phase->output_node->outgoing_links[0]->effect->effect_type_id() == "ComputeShaderOutputDisplayEffect");
+ } else {
+ is_last_phase = phase->output_node->outgoing_links.empty();
+ }
+ if (is_last_phase && output_origin == OUTPUT_ORIGIN_TOP_LEFT) {
+ if (phase->is_compute_shader) {
+ frag_shader_header += "#define FLIP_ORIGIN 1\n";
+ } else {
+ const string needle = "#define FLIP_ORIGIN 0";
+ size_t pos = vert_shader.find(needle);
+ assert(pos != string::npos);
+
+ vert_shader[pos + needle.size() - 1] = '1';