- // Obviously, the chroma plane here needs to be moved to the left,
- // which means _adding_ 0.5 to the texture coordinates when sampling
- // chroma.
- float chroma_offset_x = (0.5f - ycbcr_format.chroma_x_position) / widths[1];
- float chroma_offset_y = (0.5f - ycbcr_format.chroma_y_position) / heights[1];
+ // In other words, (0.0, 0.0) means that the chroma sample is exactly
+ // co-sited on top of the top-left luma sample. Note, however, that
+ // this is _not_ 0.5 texels to the left, since the OpenGL's texel center
+ // is in (0.5, 0.5); it is in (0.25, 0.25). In a sense, the four luma samples
+ // define a square where chroma position (0.0, 0.0) is in texel position
+ // (0.25, 0.25) and chroma position (1.0, 1.0) is in texel position (0.75, 0.75)
+ // (the outer border shows the borders of the texel itself, ie. from
+ // (0, 0) to (1, 1)):
+ //
+ // ---------
+ // | |
+ // | X---X |
+ // | | * | |
+ // | X---X |
+ // | |
+ // ---------
+ //
+ // Also note that if we have no subsampling, the square will have zero
+ // area and the chroma position does not matter at all.
+ float chroma_x_local_position =
+ (0.5 + ycbcr_format.chroma_x_position * (ycbcr_format.chroma_subsampling_x - 1)) /
+ ycbcr_format.chroma_subsampling_x;
+ float chroma_y_local_position =
+ (0.5 + ycbcr_format.chroma_y_position * (ycbcr_format.chroma_subsampling_y - 1)) /
+ ycbcr_format.chroma_subsampling_y;
+
+ float chroma_offset_x = (0.5f - chroma_x_local_position) / widths[1];
+ float chroma_offset_y = (0.5f - chroma_y_local_position) / heights[1];