tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

yuv.glsl (8208B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2  * License, v. 2.0. If a copy of the MPL was not distributed with this
      3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include shared
      6 
      7 #define YUV_FORMAT_NV12             0
      8 #define YUV_FORMAT_P010             1
      9 #define YUV_FORMAT_NV16             2
     10 #define YUV_FORMAT_PLANAR           3
     11 #define YUV_FORMAT_INTERLEAVED      4
     12 
     13 //#define YUV_PRECISION mediump
     14 #define YUV_PRECISION highp
     15 
     16 #ifdef WR_VERTEX_SHADER
     17 
     18 #ifdef WR_FEATURE_TEXTURE_RECT
     19     #define TEX_SIZE_YUV(sampler) vec2(1.0)
     20 #else
     21     #define TEX_SIZE_YUV(sampler) vec2(TEX_SIZE(sampler).xy)
     22 #endif
     23 
     24 // `YuvRangedColorSpace`
     25 #define YUV_COLOR_SPACE_REC601_NARROW  0
     26 #define YUV_COLOR_SPACE_REC601_FULL    1
     27 #define YUV_COLOR_SPACE_REC709_NARROW  2
     28 #define YUV_COLOR_SPACE_REC709_FULL    3
     29 #define YUV_COLOR_SPACE_REC2020_NARROW 4
     30 #define YUV_COLOR_SPACE_REC2020_FULL   5
     31 #define YUV_COLOR_SPACE_GBR_IDENTITY   6
     32 
     33 // The constants added to the Y, U and V components are applied in the fragment shader.
     34 
     35 // `rgbFromYuv` from https://jdashg.github.io/misc/colors/from-coeffs.html
     36 // The matrix is stored in column-major.
     37 const mat3 RgbFromYuv_Rec601 = mat3(
     38   1.00000, 1.00000, 1.00000,
     39   0.00000,-0.17207, 0.88600,
     40   0.70100,-0.35707, 0.00000
     41 );
     42 const mat3 RgbFromYuv_Rec709 = mat3(
     43   1.00000, 1.00000, 1.00000,
     44   0.00000,-0.09366, 0.92780,
     45   0.78740,-0.23406, 0.00000
     46 );
     47 const mat3 RgbFromYuv_Rec2020 = mat3(
     48   1.00000, 1.00000, 1.00000,
     49   0.00000,-0.08228, 0.94070,
     50   0.73730,-0.28568, 0.00000
     51 );
     52 
     53 // The matrix is stored in column-major.
     54 // Identity is stored as GBR
     55 const mat3 RgbFromYuv_GbrIdentity = mat3(
     56     0.0              ,  1.0,                0.0,
     57     0.0              ,  0.0,                1.0,
     58     1.0              ,  0.0,                0.0
     59 );
     60 
     61 // -
     62 
     63 struct YuvPrimitive {
     64     int channel_bit_depth;
     65     int color_space;
     66     int yuv_format;
     67 };
     68 
     69 struct YuvColorSamplingInfo {
     70     mat3 rgb_from_yuv;
     71     vec4 packed_zero_one_vals;
     72 };
     73 
     74 struct YuvColorMatrixInfo {
     75     vec3 ycbcr_bias;
     76     mat3 rgb_from_debiased_ycbrc;
     77 };
     78 
     79 // -
     80 
     81 vec4 yuv_channel_zero_one_identity(int bit_depth, float channel_max) {
     82     float all_ones_normalized = float((1 << bit_depth) - 1) / channel_max;
     83     return vec4(0.0, 0.0, all_ones_normalized, all_ones_normalized);
     84 }
     85 
     86 vec4 yuv_channel_zero_one_narrow_range(int bit_depth, float channel_max) {
     87     // Note: 512/1023 != 128/255
     88     ivec4 zero_one_ints = ivec4(16, 128, 235, 240) << (bit_depth - 8);
     89     return vec4(zero_one_ints) / channel_max;
     90 }
     91 
     92 vec4 yuv_channel_zero_one_full_range(int bit_depth, float channel_max) {
     93     vec4 narrow = yuv_channel_zero_one_narrow_range(bit_depth, channel_max);
     94     vec4 identity = yuv_channel_zero_one_identity(bit_depth, channel_max);
     95     return vec4(0.0, narrow.y, identity.z, identity.w);
     96 }
     97 
     98 YuvColorSamplingInfo get_yuv_color_info(YuvPrimitive prim) {
     99     float channel_max = 255.0;
    100     if (prim.channel_bit_depth > 8) {
    101         if (prim.yuv_format == YUV_FORMAT_P010) {
    102             // This is an MSB format.
    103             channel_max = float((1 << prim.channel_bit_depth) - 1);
    104         } else {
    105             // For >8bpc, we get the low bits, not the high bits:
    106             // 10bpc(1.0): 0b0000_0011_1111_1111
    107             channel_max = 65535.0;
    108         }
    109     }
    110     if (prim.color_space == YUV_COLOR_SPACE_REC601_NARROW) {
    111         return YuvColorSamplingInfo(RgbFromYuv_Rec601,
    112                 yuv_channel_zero_one_narrow_range(prim.channel_bit_depth, channel_max));
    113     } else if (prim.color_space == YUV_COLOR_SPACE_REC601_FULL) {
    114         return YuvColorSamplingInfo(RgbFromYuv_Rec601,
    115                 yuv_channel_zero_one_full_range(prim.channel_bit_depth, channel_max));
    116 
    117     } else if (prim.color_space == YUV_COLOR_SPACE_REC709_NARROW) {
    118         return YuvColorSamplingInfo(RgbFromYuv_Rec709,
    119                 yuv_channel_zero_one_narrow_range(prim.channel_bit_depth, channel_max));
    120     } else if (prim.color_space == YUV_COLOR_SPACE_REC709_FULL) {
    121         return YuvColorSamplingInfo(RgbFromYuv_Rec709,
    122                 yuv_channel_zero_one_full_range(prim.channel_bit_depth, channel_max));
    123 
    124     } else if (prim.color_space == YUV_COLOR_SPACE_REC2020_NARROW) {
    125         return YuvColorSamplingInfo(RgbFromYuv_Rec2020,
    126                 yuv_channel_zero_one_narrow_range(prim.channel_bit_depth, channel_max));
    127     } else if (prim.color_space == YUV_COLOR_SPACE_REC2020_FULL) {
    128         return YuvColorSamplingInfo(RgbFromYuv_Rec2020,
    129                 yuv_channel_zero_one_full_range(prim.channel_bit_depth, channel_max));
    130 
    131     } else {
    132         // Identity
    133         return YuvColorSamplingInfo(RgbFromYuv_GbrIdentity,
    134                 yuv_channel_zero_one_identity(prim.channel_bit_depth, channel_max));
    135     }
    136 }
    137 
    138 YuvColorMatrixInfo get_rgb_from_ycbcr_info(YuvPrimitive prim) {
    139     YuvColorSamplingInfo info = get_yuv_color_info(prim);
    140 
    141     vec2 zero = info.packed_zero_one_vals.xy;
    142     vec2 one = info.packed_zero_one_vals.zw;
    143     // Such that yuv_value = (ycbcr_sample - zero) / (one - zero)
    144     vec2 scale = 1.0 / (one - zero);
    145 
    146     YuvColorMatrixInfo mat_info;
    147     mat_info.ycbcr_bias = zero.xyy;
    148     mat3 yuv_from_debiased_ycbcr = mat3(scale.x,     0.0,     0.0,
    149                                             0.0, scale.y,     0.0,
    150                                             0.0,     0.0, scale.y);
    151     mat_info.rgb_from_debiased_ycbrc = info.rgb_from_yuv * yuv_from_debiased_ycbcr;
    152     return mat_info;
    153 }
    154 
    155 void write_uv_rect(
    156     vec2 uv0,
    157     vec2 uv1,
    158     vec2 f,
    159     vec2 texture_size,
    160     out vec2 uv,
    161     out vec4 uv_bounds
    162 ) {
    163     uv = mix(uv0, uv1, f);
    164 
    165     uv_bounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5));
    166 
    167     #ifndef WR_FEATURE_TEXTURE_RECT
    168         uv /= texture_size;
    169         uv_bounds /= texture_size.xyxy;
    170     #endif
    171 }
    172 #endif
    173 
    174 #ifdef WR_FRAGMENT_SHADER
    175 
    176 vec4 sample_yuv(
    177     int format,
    178     YUV_PRECISION vec3 ycbcr_bias,
    179     YUV_PRECISION mat3 rgb_from_debiased_ycbrc,
    180     vec2 in_uv_y,
    181     vec2 in_uv_u,
    182     vec2 in_uv_v,
    183     vec4 uv_bounds_y,
    184     vec4 uv_bounds_u,
    185     vec4 uv_bounds_v
    186 ) {
    187     YUV_PRECISION vec3 ycbcr_sample;
    188 
    189     switch (format) {
    190         case YUV_FORMAT_PLANAR:
    191             {
    192                 // The yuv_planar format should have this third texture coordinate.
    193                 vec2 uv_y = clamp(in_uv_y, uv_bounds_y.xy, uv_bounds_y.zw);
    194                 vec2 uv_u = clamp(in_uv_u, uv_bounds_u.xy, uv_bounds_u.zw);
    195                 vec2 uv_v = clamp(in_uv_v, uv_bounds_v.xy, uv_bounds_v.zw);
    196                 ycbcr_sample.x = TEX_SAMPLE(sColor0, uv_y).r;
    197                 ycbcr_sample.y = TEX_SAMPLE(sColor1, uv_u).r;
    198                 ycbcr_sample.z = TEX_SAMPLE(sColor2, uv_v).r;
    199             }
    200             break;
    201 
    202         case YUV_FORMAT_NV12:
    203         case YUV_FORMAT_P010:
    204         case YUV_FORMAT_NV16:
    205             {
    206                 vec2 uv_y = clamp(in_uv_y, uv_bounds_y.xy, uv_bounds_y.zw);
    207                 vec2 uv_uv = clamp(in_uv_u, uv_bounds_u.xy, uv_bounds_u.zw);
    208                 ycbcr_sample.x = TEX_SAMPLE(sColor0, uv_y).r;
    209                 ycbcr_sample.yz = TEX_SAMPLE(sColor1, uv_uv).rg;
    210             }
    211             break;
    212 
    213         case YUV_FORMAT_INTERLEAVED:
    214             {
    215                 // "The Y, Cb and Cr color channels within the 422 data are mapped into
    216                 // the existing green, blue and red color channels."
    217                 // https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_rgb_422.txt
    218                 vec2 uv_y = clamp(in_uv_y, uv_bounds_y.xy, uv_bounds_y.zw);
    219                 ycbcr_sample = TEX_SAMPLE(sColor0, uv_y).gbr;
    220             }
    221             break;
    222 
    223         default:
    224             ycbcr_sample = vec3(0.0);
    225             break;
    226     }
    227     //if (true) return vec4(ycbcr_sample, 1.0);
    228 
    229     // See the YuvColorMatrix definition for an explanation of where the constants come from.
    230     YUV_PRECISION vec3 rgb = rgb_from_debiased_ycbrc * (ycbcr_sample - ycbcr_bias);
    231 
    232     #if defined(WR_FEATURE_ALPHA_PASS) && defined(SWGL_CLIP_MASK)
    233         // Avoid out-of-range RGB values that can mess with blending. These occur due to invalid
    234         // YUV values outside the mappable space that never the less can be generated.
    235         rgb = clamp(rgb, 0.0, 1.0);
    236     #endif
    237     return vec4(rgb, 1.0);
    238 }
    239 #endif