Make effect_id phase-local instead of global.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 18 Jan 2014 21:07:29 +0000 (22:07 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 18 Jan 2014 21:07:29 +0000 (22:07 +0100)
This is mainly to reduce the number of substantially identical shaders
we have to keep around and compile; even though two chains may be
different, often, some phase (and very often, a large one at that)
will be similar. However, in the old system, since effects had global
IDs, a change in an earlier phase would displace identifiers in a
later one, and the shader would be uncacheable.

Note that this means that an effect can actually have multiple effect_ids
now (since it could already be part of multiple phases). This is the
reason why we can't just keep having a single effect_id on the node
that we set phase-locally; it really needs to be different between phases.

effect_chain.cpp
effect_chain.h

index e6ba841..f324d1d 100644 (file)
@@ -80,13 +80,9 @@ Node *EffectChain::add_node(Effect *effect)
                assert(nodes[i]->effect != effect);
        }
 
-       char effect_id[256];
-       sprintf(effect_id, "eff%u", (unsigned)nodes.size());
-
        Node *node = new Node;
        node->effect = effect;
        node->disabled = false;
-       node->effect_id = effect_id;
        node->output_color_space = COLORSPACE_INVALID;
        node->output_gamma_curve = GAMMA_INVALID;
        node->output_alpha_type = ALPHA_INVALID;
@@ -224,6 +220,7 @@ Phase *EffectChain::compile_glsl_program(
        const std::vector<Node *> &inputs,
        const std::vector<Node *> &effects)
 {
+       Phase *phase = new Phase;
        assert(!effects.empty());
 
        // Deduplicate the inputs.
@@ -237,10 +234,13 @@ Phase *EffectChain::compile_glsl_program(
        // Create functions for all the texture inputs that we need.
        for (unsigned i = 0; i < true_inputs.size(); ++i) {
                Node *input = true_inputs[i];
+               char effect_id[256];
+               sprintf(effect_id, "in%u", i);
+               phase->effect_ids.insert(std::make_pair(input, effect_id));
        
-               frag_shader += std::string("uniform sampler2D tex_") + input->effect_id + ";\n";
-               frag_shader += std::string("vec4 ") + input->effect_id + "(vec2 tc) {\n";
-               frag_shader += "\treturn texture2D(tex_" + input->effect_id + ", tc);\n";
+               frag_shader += std::string("uniform sampler2D tex_") + effect_id + ";\n";
+               frag_shader += std::string("vec4 ") + effect_id + "(vec2 tc) {\n";
+               frag_shader += "\treturn texture2D(tex_" + std::string(effect_id) + ", tc);\n";
                frag_shader += "}\n";
                frag_shader += "\n";
        }
@@ -249,21 +249,24 @@ Phase *EffectChain::compile_glsl_program(
 
        for (unsigned i = 0; i < sorted_effects.size(); ++i) {
                Node *node = sorted_effects[i];
+               char effect_id[256];
+               sprintf(effect_id, "eff%u", i);
+               phase->effect_ids.insert(std::make_pair(node, effect_id));
 
                if (node->incoming_links.size() == 1) {
-                       frag_shader += std::string("#define INPUT ") + node->incoming_links[0]->effect_id + "\n";
+                       frag_shader += std::string("#define INPUT ") + phase->effect_ids[node->incoming_links[0]] + "\n";
                } else {
                        for (unsigned j = 0; j < node->incoming_links.size(); ++j) {
                                char buf[256];
-                               sprintf(buf, "#define INPUT%d %s\n", j + 1, node->incoming_links[j]->effect_id.c_str());
+                               sprintf(buf, "#define INPUT%d %s\n", j + 1, phase->effect_ids[node->incoming_links[j]].c_str());
                                frag_shader += buf;
                        }
                }
        
                frag_shader += "\n";
-               frag_shader += std::string("#define FUNCNAME ") + node->effect_id + "\n";
-               frag_shader += replace_prefix(node->effect->output_convenience_uniforms(), node->effect_id);
-               frag_shader += replace_prefix(node->effect->output_fragment_shader(), node->effect_id);
+               frag_shader += std::string("#define FUNCNAME ") + effect_id + "\n";
+               frag_shader += replace_prefix(node->effect->output_convenience_uniforms(), effect_id);
+               frag_shader += replace_prefix(node->effect->output_fragment_shader(), effect_id);
                frag_shader += "#undef PREFIX\n";
                frag_shader += "#undef FUNCNAME\n";
                if (node->incoming_links.size() == 1) {
@@ -285,10 +288,9 @@ Phase *EffectChain::compile_glsl_program(
                        CHECK(node->effect->set_int("needs_mipmaps", input_needs_mipmaps));
                }
        }
-       frag_shader += std::string("#define INPUT ") + sorted_effects.back()->effect_id + "\n";
+       frag_shader += std::string("#define INPUT ") + phase->effect_ids[sorted_effects.back()] + "\n";
        frag_shader.append(read_file("footer.frag"));
 
-       Phase *phase = new Phase;
        phase->glsl_program_num = resource_pool->compile_glsl_program(read_file("vs.vert"), frag_shader);
        phase->input_needs_mipmaps = input_needs_mipmaps;
        phase->inputs = true_inputs;
@@ -1537,7 +1539,7 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
                                check_error();
                        }
 
-                       std::string texture_name = std::string("tex_") + input->effect_id;
+                       std::string texture_name = std::string("tex_") + phases[phase]->effect_ids[input];
                        glUniform1i(glGetUniformLocation(phases[phase]->glsl_program_num, texture_name.c_str()), sampler);
                        check_error();
                }
@@ -1572,7 +1574,7 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
                unsigned sampler_num = phases[phase]->inputs.size();
                for (unsigned i = 0; i < phases[phase]->effects.size(); ++i) {
                        Node *node = phases[phase]->effects[i];
-                       node->effect->set_gl_state(phases[phase]->glsl_program_num, node->effect_id, &sampler_num);
+                       node->effect->set_gl_state(phases[phase]->glsl_program_num, phases[phase]->effect_ids[node], &sampler_num);
                        check_error();
                }
 
index 1078027..6cd689d 100644 (file)
@@ -57,9 +57,6 @@ public:
        std::vector<Node *> incoming_links;
 
 private:
-       // Identifier used to create unique variables in GLSL.
-       std::string effect_id;
-
        // Logical size of the output of this effect, ie. the resolution
        // you would get if you sampled it as a texture. If it is undefined
        // (since the inputs differ in resolution), it will be 0x0.
@@ -93,6 +90,10 @@ struct Phase {
 
        std::vector<Node *> effects;  // In order.
        unsigned output_width, output_height, virtual_output_width, virtual_output_height;
+
+       // Identifier used to create unique variables in GLSL.
+       // Unique per-phase to increase cacheability of compiled shaders.
+       std::map<Node *, std::string> effect_ids;
 };
 
 class EffectChain {