+ // If you have both RGBA and Y'CbCr output(s), the RGBA output will come
+ // in the last draw buffer. Also, <format> and <alpha_format> must be
+ // identical between the two.
+ void add_ycbcr_output(const ImageFormat &format, OutputAlphaFormat alpha_format,
+ const YCbCrFormat &ycbcr_format,
+ YCbCrOutputSplitting output_splitting = YCBCR_OUTPUT_INTERLEAVED,
+ GLenum output_type = GL_UNSIGNED_BYTE);
+
+ // Change Y'CbCr output format. (This can be done also after finalize()).
+ // Note that you are not allowed to change subsampling parameters;
+ // however, you can change the color space parameters, ie.,
+ // luma_coefficients, full_range and num_levels.
+ void change_ycbcr_output_format(const YCbCrFormat &ycbcr_format);
+
+ // Set number of output bits, to scale the dither.
+ // 8 is the right value for most outputs.
+ //
+ // Special note for 10- and 12-bit Y'CbCr packed into GL_UNSIGNED_SHORT:
+ // This is relative to the actual output, not the logical one, so you should
+ // specify 16 here, not 10 or 12.
+ //
+ // The default, 0, is a special value that means no dither.
+ void set_dither_bits(unsigned num_bits)
+ {
+ this->num_dither_bits = num_bits;
+ }
+
+ // Set where (0,0) is taken to be in the output. The default is
+ // OUTPUT_ORIGIN_BOTTOM_LEFT, which is usually what you want
+ // (see OutputOrigin above for more details).
+ void set_output_origin(OutputOrigin output_origin)
+ {
+ this->output_origin = output_origin;
+ }
+
+ // Set intermediate format for framebuffers used when we need to bounce
+ // to a temporary texture. The default, GL_RGBA16F, is good for most uses;
+ // it is precise, has good range, and is relatively efficient. However,
+ // if you need even more speed and your chain can do with some loss of
+ // accuracy, you can change the format here (before calling finalize).
+ // Calculations between bounce buffers are still in 32-bit floating-point
+ // no matter what you specify.
+ //
+ // Of special interest is GL_SRGB8_ALPHA8, which stores sRGB-encoded RGB
+ // and linear alpha; this is half the memory bandwidth of GL_RGBA16F,
+ // while retaining reasonable precision for typical image data. It will,
+ // however, cause some gamut clipping if your colorspace is far from sRGB,
+ // as it cannot represent values outside [0,1]. NOTE: If you construct
+ // a chain where you end up bouncing pixels in non-linear light
+ // (gamma different from GAMMA_LINEAR), this will be the wrong thing.
+ // However, it's hard to see how this could happen in a non-contrived
+ // chain; few effects ever need texture bounce or resizing without also
+ // combining multiple pixels, which really needs linear light and thus
+ // triggers a conversion before the bounce.
+ //
+ // If you don't need alpha (or can do with very little of it), GL_RGB10_A2
+ // is even better, as it has two more bits for each color component. There
+ // is no GL_SRGB10, unfortunately, so on its own, it is somewhat worse than
+ // GL_SRGB8, but you can set <transformation> to SQUARE_ROOT_FRAMEBUFFER_TRANSFORMATION,
+ // and sqrt(x) will be stored instead of x. This is a rough approximation to
+ // the sRGB curve, and reduces maximum error (in sRGB distance) by almost an
+ // order of magnitude, well below what you can get from 8-bit true sRGB.
+ // (Note that this strategy avoids the problem with bounced non-linear data
+ // above, since the square root is turned off in that case.) However, texture
+ // filtering will happen on the transformed values, so if you have heavy
+ // downscaling or the likes (e.g. mipmaps), you could get subtly bad results.
+ // You'll need to see which of the two that works the best for you in practice.
+ void set_intermediate_format(
+ GLenum intermediate_format,
+ FramebufferTransformation transformation = NO_FRAMEBUFFER_TRANSFORMATION)
+ {
+ this->intermediate_format = intermediate_format;
+ this->intermediate_transformation = transformation;
+ }