EffectChain::EffectChain(float aspect_nom, float aspect_denom, ResourcePool *resource_pool)
: aspect_nom(aspect_nom),
aspect_denom(aspect_denom),
+ output_color_rgba(false),
+ output_color_ycbcr(false),
dither_effect(NULL),
num_dither_bits(0),
output_origin(OUTPUT_ORIGIN_BOTTOM_LEFT),
void EffectChain::add_output(const ImageFormat &format, OutputAlphaFormat alpha_format)
{
assert(!finalized);
+ assert(!output_color_rgba);
output_format = format;
output_alpha_format = alpha_format;
- output_color_type = OUTPUT_COLOR_RGB;
+ output_color_rgba = true;
}
void EffectChain::add_ycbcr_output(const ImageFormat &format, OutputAlphaFormat alpha_format,
const YCbCrFormat &ycbcr_format, YCbCrOutputSplitting output_splitting)
{
assert(!finalized);
+ assert(!output_color_ycbcr);
output_format = format;
output_alpha_format = alpha_format;
- output_color_type = OUTPUT_COLOR_YCBCR;
+ output_color_ycbcr = true;
output_ycbcr_format = ycbcr_format;
output_ycbcr_splitting = output_splitting;
return GL_TEXTURE0 + node->incoming_links[input_num]->bound_sampler_num;
}
+GLenum EffectChain::has_input_sampler(Node *node, unsigned input_num) const
+{
+ assert(input_num < node->incoming_links.size());
+ return node->incoming_links[input_num]->bound_sampler_num >= 0 &&
+ node->incoming_links[input_num]->bound_sampler_num < 8;
+}
+
void EffectChain::find_all_nonlinear_inputs(Node *node, vector<Node *> *nonlinear_inputs)
{
if (node->output_gamma_curve == GAMMA_LINEAR &&
return effect;
}
-// GLSL pre-1.30 doesn't support token pasting. Replace PREFIX(x) with <effect_id>_x.
+// ESSL doesn't support token pasting. Replace PREFIX(x) with <effect_id>_x.
string replace_prefix(const string &text, const string &prefix)
{
string output;
frag_shader += string("#define INPUT ") + phase->effect_ids[phase->effects.back()] + "\n";
// If we're the last phase, add the right #defines for Y'CbCr multi-output as needed.
- if (phase->output_node->outgoing_links.empty() && output_color_type == OUTPUT_COLOR_YCBCR) {
+ 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");
+ }
}
- frag_shader.append(read_version_dependent_file("footer", "frag"));
+ 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
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);
}
vert_shader[pos + needle.size() - 1] = '1';
}
- phase->glsl_program_num = resource_pool->compile_glsl_program(vert_shader, frag_shader);
+ phase->glsl_program_num = resource_pool->compile_glsl_program(vert_shader, frag_shader, frag_shader_outputs);
// Collect the resulting location numbers for each uniform.
collect_uniform_locations(phase->glsl_program_num, &phase->uniforms_sampler2d);
bool start_new_phase = false;
if (node->effect->needs_texture_bounce() &&
- !deps[i]->effect->is_single_texture()) {
+ !deps[i]->effect->is_single_texture() &&
+ !deps[i]->effect->override_disable_bounce()) {
start_new_phase = true;
}
// and create a GLSL program for it.
assert(!phase->effects.empty());
- // Deduplicate the inputs.
- sort(phase->inputs.begin(), phase->inputs.end());
- phase->inputs.erase(unique(phase->inputs.begin(), phase->inputs.end()), phase->inputs.end());
+ // Deduplicate the inputs, but don't change the ordering e.g. by sorting;
+ // that would be nondeterministic and thus reduce cacheability.
+ // TODO: Make this even more deterministic.
+ vector<Phase *> dedup_inputs;
+ set<Phase *> seen_inputs;
+ for (size_t i = 0; i < phase->inputs.size(); ++i) {
+ if (seen_inputs.insert(phase->inputs[i]).second) {
+ dedup_inputs.push_back(phase->inputs[i]);
+ }
+ }
+ swap(phase->inputs, dedup_inputs);
// Allocate samplers for each input.
phase->input_samplers.resize(phase->inputs.size());
// gamma-encoded data.
void EffectChain::add_ycbcr_conversion_if_needed()
{
- assert(output_color_type == OUTPUT_COLOR_RGB || output_color_type == OUTPUT_COLOR_YCBCR);
- if (output_color_type != OUTPUT_COLOR_YCBCR) {
+ assert(output_color_rgba || output_color_ycbcr);
+ if (!output_color_ycbcr) {
return;
}
Node *output = find_output_node();
{
assert(finalized);
+ // This needs to be set anew, in case we are coming from a different context
+ // from when we initialized.
+ check_error();
+ glDisable(GL_DITHER);
+ check_error();
+
// Save original viewport.
GLuint x = 0, y = 0;
}
// Basic state.
+ check_error();
glDisable(GL_BLEND);
check_error();
glDisable(GL_DEPTH_TEST);