+ void render_to_texture(const std::vector<DestinationTexture> &destinations, unsigned width, unsigned height);
+
+ Effect *last_added_effect() {
+ if (nodes.empty()) {
+ return nullptr;
+ } else {
+ return nodes.back()->effect;
+ }
+ }
+
+ // API for manipulating the graph directly. Intended to be used from
+ // effects and by EffectChain itself.
+ //
+ // Note that for nodes with multiple inputs, the order of calls to
+ // connect_nodes() will matter.
+ Node *add_node(Effect *effect);
+ void connect_nodes(Node *sender, Node *receiver);
+ void replace_receiver(Node *old_receiver, Node *new_receiver);
+ void replace_sender(Node *new_sender, Node *receiver);
+ void insert_node_between(Node *sender, Node *middle, Node *receiver);
+ Node *find_node_for_effect(Effect *effect) { return node_map[effect]; }
+
+ // Get the OpenGL sampler (GL_TEXTURE0, GL_TEXTURE1, etc.) for the
+ // input of the given node, so that one can modify the sampler state
+ // directly. Only valid to call during set_gl_state().
+ //
+ // Also, for this to be allowed, <node>'s effect must have
+ // needs_texture_bounce() set, so that it samples directly from a
+ // single-sampler input, or from an RTT texture.
+ GLenum get_input_sampler(Node *node, unsigned input_num) const;
+
+ // Whether input <input_num> of <node> corresponds to a single sampler
+ // (see get_input_sampler()). Normally, you should not need to call this;
+ // however, if the input Effect has set override_texture_bounce(),
+ // this will return false, and you could be flexible and check it first
+ // if you want.
+ GLenum has_input_sampler(Node *node, unsigned input_num) const;
+
+ // Get the current resource pool assigned to this EffectChain.
+ // Primarily to let effects allocate textures as needed.
+ // Any resources you get from the pool must be returned to the pool
+ // no later than in the Effect's destructor.
+ ResourcePool *get_resource_pool() { return resource_pool; }
+
+private:
+ // Make sure the output rectangle is at least large enough to hold
+ // the given input rectangle in both dimensions, and is of the
+ // current aspect ratio (aspect_nom/aspect_denom).
+ void size_rectangle_to_fit(unsigned width, unsigned height, unsigned *output_width, unsigned *output_height);
+
+ // Compute the input sizes for all inputs for all effects in a given phase,
+ // and inform the effects about the results.
+ void inform_input_sizes(Phase *phase);
+
+ // Determine the preferred output size of a given phase.
+ // Requires that all input phases (if any) already have output sizes set.
+ void find_output_size(Phase *phase);
+
+ // Find all inputs eventually feeding into this effect that have
+ // output gamma different from GAMMA_LINEAR.
+ void find_all_nonlinear_inputs(Node *effect, std::vector<Node *> *nonlinear_inputs);
+
+ // Create a GLSL program computing the effects for this phase in order.
+ void compile_glsl_program(Phase *phase);
+
+ // Create all GLSL programs needed to compute the given effect, and all outputs
+ // that depend on it (whenever possible). Returns the phase that has <output>
+ // as the last effect. Also pushes all phases in order onto <phases>.
+ Phase *construct_phase(Node *output, std::map<Node *, Phase *> *completed_effects);
+
+ // Do the actual rendering of the chain. If <dest_fbo> is not (GLuint)-1,
+ // renders to that FBO. If <destinations> is non-empty, render to that set
+ // of textures (last phase, save for the dummy phase, must be a compute shader),
+ // with x/y ignored. Having both set is an error.
+ void render(GLuint dest_fbo, const std::vector<DestinationTexture> &destinations,
+ unsigned x, unsigned y, unsigned width, unsigned height);
+
+ // Execute one phase, ie. set up all inputs, effects and outputs, and render the quad.
+ // If <destinations> is empty, uses whatever output is current (and the phase must not be
+ // a compute shader).
+ void execute_phase(Phase *phase,
+ const std::map<Phase *, GLuint> &output_textures,
+ const std::vector<DestinationTexture> &destinations,
+ std::set<Phase *> *generated_mipmaps);