+
+ // If we're the last phase, add the right #defines for Y'CbCr multi-output as needed.
+ vector<string> frag_shader_outputs; // In order.
+ if (phase->output_node->outgoing_links.empty() && output_color_ycbcr) {
+ switch (output_ycbcr_splitting) {
+ case YCBCR_OUTPUT_INTERLEAVED:
+ // No #defines set.
+ frag_shader_outputs.push_back("FragColor");
+ break;
+ case YCBCR_OUTPUT_SPLIT_Y_AND_CBCR:
+ frag_shader += "#define YCBCR_OUTPUT_SPLIT_Y_AND_CBCR 1\n";
+ frag_shader_outputs.push_back("Y");
+ frag_shader_outputs.push_back("Chroma");
+ break;
+ case YCBCR_OUTPUT_PLANAR:
+ frag_shader += "#define YCBCR_OUTPUT_PLANAR 1\n";
+ frag_shader_outputs.push_back("Y");
+ frag_shader_outputs.push_back("Cb");
+ frag_shader_outputs.push_back("Cr");
+ break;
+ default:
+ assert(false);
+ }
+
+ if (output_color_rgba) {
+ // Note: Needs to come in the header, because not only the
+ // output needs to see it (YCbCrConversionEffect and DitherEffect
+ // do, too).
+ frag_shader_header += "#define YCBCR_ALSO_OUTPUT_RGBA 1\n";
+ frag_shader_outputs.push_back("RGBA");
+ }
+ }
+
+ // 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";
+ }
+ }
+
+ 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[node];
+ 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_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);
+ }
+
+ frag_shader = frag_shader_header + frag_shader_uniforms + frag_shader;