/usr/include/movit/effect.h is in libmovit-dev 1.3.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 | #ifndef _MOVIT_EFFECT_H
#define _MOVIT_EFFECT_H 1
// Effect is the base class for every effect. It basically represents a single
// GLSL function, with an optional set of user-settable parameters.
//
// A note on naming: Since all effects run in the same GLSL namespace,
// you can't use any name you want for global variables (e.g. uniforms).
// The framework assigns a prefix to you which will be unique for each
// effect instance; use the macro PREFIX() around your identifiers to
// automatically prepend that prefix.
#include <epoxy/gl.h>
#include <assert.h>
#include <stddef.h>
#include <map>
#include <string>
#include <vector>
#include <Eigen/Core>
#include "defs.h"
namespace movit {
class EffectChain;
class Node;
// Can alias on a float[2].
struct Point2D {
Point2D() {}
Point2D(float x, float y)
: x(x), y(y) {}
float x, y;
};
// Can alias on a float[3].
struct RGBTriplet {
RGBTriplet() {}
RGBTriplet(float r, float g, float b)
: r(r), g(g), b(b) {}
float r, g, b;
};
// Can alias on a float[4].
struct RGBATuple {
RGBATuple() {}
RGBATuple(float r, float g, float b, float a)
: r(r), g(g), b(b), a(a) {}
float r, g, b, a;
};
// Represents a registered uniform.
template<class T>
struct Uniform {
std::string name; // Without prefix.
const T *value; // Owner by the effect.
size_t num_values; // Number of elements; for arrays only. _Not_ the vector length.
std::string prefix; // Filled in only after phases have been constructed.
GLint location; // Filled in only after phases have been constructed. -1 if no location.
};
class Effect {
public:
virtual ~Effect() {}
// An identifier for this type of effect, mostly used for debug output
// (but some special names, like "ColorspaceConversionEffect", holds special
// meaning). Same as the class name is fine.
virtual std::string effect_type_id() const = 0;
// Whether this effects expects its input (and output) to be in
// linear gamma, ie. without an applied gamma curve. Most effects
// will want this, although the ones that never actually look at
// the pixels, e.g. mirror, won't need to care, and can set this
// to false. If so, the input gamma will be undefined.
//
// Also see the note on needs_texture_bounce(), below.
virtual bool needs_linear_light() const { return true; }
// Whether this effect expects its input to be in the sRGB
// color space, ie. use the sRGB/Rec. 709 RGB primaries.
// (If not, it would typically come in as some slightly different
// set of RGB primaries; you would currently not get YCbCr
// or something similar).
//
// Again, most effects will want this, but you can set it to false
// if you process each channel independently, equally _and_
// in a linear fashion.
virtual bool needs_srgb_primaries() const { return true; }
// How this effect handles alpha, ie. what it outputs in its
// alpha channel. The choices are basically blank (alpha is always 1.0),
// premultiplied and postmultiplied.
//
// Premultiplied alpha is when the alpha value has been be multiplied
// into the three color components, so e.g. 100% red at 50% alpha
// would be (0.5, 0.0, 0.0, 0.5) instead of (1.0, 0.0, 0.0, 0.5)
// as it is stored in most image formats (postmultiplied alpha).
// The multiplication is taken to have happened in linear light.
// This is the most natural format for processing, and the default in
// most of Movit (just like linear light is).
//
// If you set INPUT_AND_OUTPUT_PREMULTIPLIED_ALPHA or
// INPUT_PREMULTIPLIED_ALPHA_KEEP_BLANK, all of your inputs
// (if any) are guaranteed to also be in premultiplied alpha.
// Otherwise, you can get postmultiplied or premultiplied alpha;
// you won't know. If you have multiple inputs, you will get the same
// (pre- or postmultiplied) for all inputs, although most likely,
// you will want to combine them in a premultiplied fashion anyway
// in that case.
enum AlphaHandling {
// Always outputs blank alpha (ie. alpha=1.0). Only appropriate
// for inputs that do not output an alpha channel.
// Blank alpha is special in that it can be treated as both
// pre- and postmultiplied.
OUTPUT_BLANK_ALPHA,
// Always outputs postmultiplied alpha. Only appropriate for inputs.
OUTPUT_POSTMULTIPLIED_ALPHA,
// Always outputs premultiplied alpha. As noted above,
// you will then also get all inputs in premultiplied alpha.
// If you set this, you should also set needs_linear_light().
INPUT_AND_OUTPUT_PREMULTIPLIED_ALPHA,
// Like INPUT_AND_OUTPUT_PREMULTIPLIED_ALPHA, but also guarantees
// that if you get blank alpha in, you also keep blank alpha out.
// This is a somewhat weaker guarantee than DONT_CARE_ALPHA_TYPE,
// but is still useful in many situations, and appropriate when
// e.g. you don't touch alpha at all.
//
// Does not make sense for inputs.
INPUT_PREMULTIPLIED_ALPHA_KEEP_BLANK,
// Keeps the type of alpha (premultiplied, postmultiplied, blank)
// unchanged from input to output. Usually appropriate if you
// process all color channels in a linear fashion, do not change
// alpha, and do not produce any new pixels thare have alpha != 1.0.
//
// Does not make sense for inputs.
DONT_CARE_ALPHA_TYPE,
};
virtual AlphaHandling alpha_handling() const { return INPUT_AND_OUTPUT_PREMULTIPLIED_ALPHA; }
// Whether this effect expects its input to come directly from
// a texture. If this is true, the framework will not chain the
// input from other effects, but will store the results of the
// chain to a temporary (RGBA fp16) texture and let this effect
// sample directly from that.
//
// There are two good reasons why you might want to set this:
//
// 1. You are sampling more than once from the input,
// in which case computing all the previous steps might
// be more expensive than going to a memory intermediate.
// 2. You rely on previous effects, possibly including gamma
// expansion, to happen pre-filtering instead of post-filtering.
// (This is only relevant if you actually need the filtering; if
// you sample 1:1 between pixels and texels, it makes no difference.)
//
// Note that in some cases, you might get post-filtered gamma expansion
// even when setting this option. More specifically, if you are the
// first effect in the chain, and the GPU is doing sRGB gamma
// expansion, it is undefined (from OpenGL's side) whether expansion
// happens pre- or post-filtering. For most uses, however,
// either will be fine.
virtual bool needs_texture_bounce() const { return false; }
// Whether this effect expects mipmaps or not. If you set this to
// true, you will be sampling with bilinear filtering; if not,
// you could be sampling with simple linear filtering and no mipmaps
// (although there is no guarantee; if a different effect in the chain
// needs mipmaps, you will also get them).
virtual bool needs_mipmaps() const { return false; }
// Whether there is a direct correspondence between input and output
// texels. Specifically, the effect must not:
//
// 1. Try to sample in the border (ie., outside the 0.0 to 1.0 area).
// 2. Try to sample between texels.
// 3. Sample with an x- or y-derivative different from -1 or 1.
// (This also means needs_mipmaps() and one_to_one_sampling()
// together would make no sense.)
//
// The most common case for this would be an effect that has an exact
// 1:1-correspondence between input and output texels, e.g. SaturationEffect.
// However, more creative things, like mirroring/flipping or padding,
// would also be allowed.
//
// The primary gain from setting this is that you can sample directly
// from an effect that changes output size (see changes_output_size() below),
// without going through a bounce texture. It won't work for effects that
// set sets_virtual_output_size(), though.
//
// Does not make a lot of sense together with needs_texture_bounce().
virtual bool one_to_one_sampling() const { return false; }
// Whether this effect wants to output to a different size than
// its input(s) (see inform_input_size(), below). See also
// sets_virtual_output_size() below.
virtual bool changes_output_size() const { return false; }
// Whether your get_output_size() function (see below) intends to ever set
// virtual_width different from width, or similar for height.
// It does not make sense to set this to true if changes_output_size() is false.
virtual bool sets_virtual_output_size() const { return changes_output_size(); }
// Whether this effect is effectively sampling from a a single texture.
// If so, it will override needs_texture_bounce(); however, there are also
// two demands it needs to fulfill:
//
// 1. It needs to be an Input, ie. num_inputs() == 0.
// 2. It needs to allocate exactly one sampler in set_gl_state(),
// and allow dependent effects to change that sampler state.
virtual bool is_single_texture() const { return false; }
// If set, this effect should never be bounced to an output, even if a
// dependent effect demands texture bounce.
//
// Note that setting this can invoke undefined behavior, up to and including crashing,
// so you should only use it if you have deep understanding of your entire chain
// and Movit's processing of it. The most likely use case is if you have an input
// that's cheap to compute but not a single texture (e.g. YCbCrInput), and want
// to run a ResampleEffect directly from it. Normally, this would require a bounce,
// but it's faster not to. (However, also note that in this case, effective texel
// subpixel precision will be too optimistic, since chroma is already subsampled.)
//
// Has no effect if is_single_texture() is set.
virtual bool override_disable_bounce() const { return false; }
// If changes_output_size() is true, you must implement this to tell
// the framework what output size you want. Also, you can set a
// virtual width/height, which is the size the next effect (if any)
// will _think_ your data is in. This is primarily useful if you are
// relying on getting OpenGL's bilinear resizing for free; otherwise,
// your virtual_width/virtual_height should be the same as width/height.
//
// Note that it is explicitly allowed to change width and height
// from frame to frame; EffectChain will reallocate textures as needed.
virtual void get_output_size(unsigned *width, unsigned *height,
unsigned *virtual_width, unsigned *virtual_height) const {
assert(false);
}
// Tells the effect the resolution of each of its input.
// This will be called every frame, and always before get_output_size(),
// so you can change your output size based on the input if so desired.
//
// Note that in some cases, an input might not have a single well-defined
// resolution (for instance if you fade between two inputs with
// different resolutions). In this case, you will get width=0 and height=0
// for that input. If you cannot handle that, you will need to set
// needs_texture_bounce() to true, which will force a render to a single
// given resolution before you get the input.
virtual void inform_input_size(unsigned input_num, unsigned width, unsigned height) {}
// How many inputs this effect will take (a fixed number).
// If you have only one input, it will be called INPUT() in GLSL;
// if you have several, they will be INPUT1(), INPUT2(), and so on.
virtual unsigned num_inputs() const { return 1; }
// Inform the effect that it has been just added to the EffectChain.
// The primary use for this is to store the ResourcePool uesd by
// the chain; for modifications to it, rewrite_graph() below
// is probably a better fit.
virtual void inform_added(EffectChain *chain) {}
// Let the effect rewrite the effect chain as it sees fit.
// Most effects won't need to do this, but this is very useful
// if you have an effect that consists of multiple sub-effects
// (for instance, two passes). The effect is given to its own
// pointer, and it can add new ones (by using add_node()
// and connect_node()) as it sees fit. This is called at
// EffectChain::finalize() time, when the entire graph is known,
// in the order that the effects were originally added.
//
// Note that if the effect wants to take itself entirely out
// of the chain, it must set “disabled” to true and then disconnect
// itself from all other effects.
virtual void rewrite_graph(EffectChain *graph, Node *self) {}
// Returns the GLSL fragment shader string for this effect.
virtual std::string output_fragment_shader() = 0;
// Set all OpenGL state that this effect needs before rendering.
// The default implementation sets one uniform per registered parameter,
// but no other state.
//
// <sampler_num> is the first free texture sampler. If you want to use
// textures, you can bind a texture to GL_TEXTURE0 + <sampler_num>,
// and then increment the number (so that the next effect in the chain
// will use a different sampler).
virtual void set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num);
// If you set any special OpenGL state in set_gl_state(), you can clear it
// after rendering here. The default implementation does nothing.
virtual void clear_gl_state();
// Set a parameter; intended to be called from user code.
// Neither of these take ownership of the pointer.
virtual bool set_int(const std::string&, int value) MUST_CHECK_RESULT;
virtual bool set_float(const std::string &key, float value) MUST_CHECK_RESULT;
virtual bool set_vec2(const std::string &key, const float *values) MUST_CHECK_RESULT;
virtual bool set_vec3(const std::string &key, const float *values) MUST_CHECK_RESULT;
virtual bool set_vec4(const std::string &key, const float *values) MUST_CHECK_RESULT;
protected:
// Register a parameter. Whenever set_*() is called with the same key,
// it will update the value in the given pointer (typically a pointer
// to some private member variable in your effect). It will also
// register a uniform of the same name (plus an arbitrary prefix
// which you can access using the PREFIX macro) that you can access.
//
// Neither of these take ownership of the pointer.
// These correspond directly to int/float/vec2/vec3/vec4 in GLSL.
void register_int(const std::string &key, int *value);
void register_float(const std::string &key, float *value);
void register_vec2(const std::string &key, float *values);
void register_vec3(const std::string &key, float *values);
void register_vec4(const std::string &key, float *values);
// Register uniforms, such that they will automatically be set
// before the shader runs. This is more efficient than set_uniform_*
// in effect_util.h, because it doesn't need to do name lookups
// every time. Also, in the future, it will use uniform buffer objects
// (UBOs) if available to reduce the number of calls into the driver.
//
// May not be called after output_fragment_shader() has returned.
// The pointer must be valid for the entire lifetime of the Effect,
// since the value is pulled from it each execution. The value is
// guaranteed to be read after set_gl_state() for the effect has
// returned, so you can safely update its value from there.
//
// Note that this will also declare the uniform in the shader for you,
// so you should not do that yourself. (This is so it can be part of
// the right uniform block.) However, it is probably a good idea to
// have a commented-out declaration so that it is easier to see the
// type and thus understand the shader on its own.
//
// Calling register_* will automatically imply register_uniform_*,
// except for register_int as noted above.
void register_uniform_sampler2d(const std::string &key, const int *value);
void register_uniform_bool(const std::string &key, const bool *value);
void register_uniform_int(const std::string &key, const int *value); // Note: Requires GLSL 1.30 or newer.
void register_uniform_float(const std::string &key, const float *value);
void register_uniform_vec2(const std::string &key, const float *values);
void register_uniform_vec3(const std::string &key, const float *values);
void register_uniform_vec4(const std::string &key, const float *values);
void register_uniform_float_array(const std::string &key, const float *values, size_t num_values);
void register_uniform_vec2_array(const std::string &key, const float *values, size_t num_values);
void register_uniform_vec3_array(const std::string &key, const float *values, size_t num_values);
void register_uniform_vec4_array(const std::string &key, const float *values, size_t num_values);
void register_uniform_mat3(const std::string &key, const Eigen::Matrix3d *matrix);
private:
std::map<std::string, int *> params_int;
std::map<std::string, float *> params_float;
std::map<std::string, float *> params_vec2;
std::map<std::string, float *> params_vec3;
std::map<std::string, float *> params_vec4;
// Picked out by EffectChain during finalization.
std::vector<Uniform<int> > uniforms_sampler2d;
std::vector<Uniform<bool> > uniforms_bool;
std::vector<Uniform<int> > uniforms_int;
std::vector<Uniform<float> > uniforms_float;
std::vector<Uniform<float> > uniforms_vec2;
std::vector<Uniform<float> > uniforms_vec3;
std::vector<Uniform<float> > uniforms_vec4;
std::vector<Uniform<float> > uniforms_float_array;
std::vector<Uniform<float> > uniforms_vec2_array;
std::vector<Uniform<float> > uniforms_vec3_array;
std::vector<Uniform<float> > uniforms_vec4_array;
std::vector<Uniform<Eigen::Matrix3d> > uniforms_mat3;
friend class EffectChain;
};
} // namespace movit
#endif // !defined(_MOVIT_EFFECT_H)
|